Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Sistem notifikasi menggunakan php dan mysql

Nah pertanyaan ini berumur 9 bulan jadi saya tidak yakin apakah OP masih membutuhkan jawaban tetapi karena banyak pandangan dan karunia yang enak, saya juga ingin menambahkan mustard saya (pepatah Jerman..).

Dalam posting ini saya akan mencoba membuat contoh sederhana yang dijelaskan tentang cara memulai membangun sistem notifikasi.

Sunting: Baiklah, ini ternyata jauh, jauh, jauh lebih lama dari yang saya harapkan. Saya benar-benar lelah pada akhirnya, maafkan saya.

WTLDR;

Pertanyaan 1: memiliki bendera di setiap notifikasi.

Pertanyaan 2: Tetap simpan setiap notifikasi sebagai satu catatan di dalam database Anda dan kelompokkan saat diminta.

Struktur

Saya berasumsi bahwa notifikasi akan terlihat seperti:

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

Di balik tirai ini bisa terlihat seperti ini:

+--------+-----------+--------+-----------------+-------------------------------------------+
| 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. |
+--------+-----------+--------+-----------------+-------------------------------------------+

Catatan: Saya tidak merekomendasikan untuk mengelompokkan notifikasi di dalam database, lakukan itu saat runtime ini membuat segalanya jauh lebih fleksibel.

  • Belum dibaca
    Setiap notifikasi harus memiliki tanda untuk menunjukkan jika penerima telah membuka notifikasi.
  • Penerima
    Menentukan siapa yang menerima notifikasi.
  • Pengirim
    Menentukan siapa yang memicu notifikasi.
  • Jenis
    Alih-alih membuat setiap Pesan dalam teks biasa di dalam database Anda, buatlah tipe. Dengan cara ini Anda dapat membuat penangan khusus untuk berbagai jenis notifikasi di dalam backend Anda. Akan mengurangi jumlah data yang disimpan di dalam basis data Anda dan memberi Anda lebih banyak fleksibilitas, memungkinkan penerjemahan pemberitahuan yang mudah, perubahan pesan sebelumnya, dll.
  • Referensi
    Sebagian besar notifikasi akan memiliki Referensi ke catatan di database atau aplikasi Anda.

Setiap sistem yang saya kerjakan memiliki 1 banding 1 simple yang sederhana hubungan referensi pada pemberitahuan, Anda mungkin memiliki 1 hingga n ingatlah bahwa saya akan melanjutkan contoh saya dengan 1:1. Ini juga berarti bahwa saya tidak memerlukan bidang yang mendefinisikan jenis objek apa yang dirujuk karena ini ditentukan oleh jenis pemberitahuan.

Tabel SQL

Sekarang ketika mendefinisikan struktur tabel nyata untuk SQL, kita sampai pada beberapa keputusan dalam hal desain database. Saya akan menggunakan solusi paling sederhana yang akan terlihat seperti ini:

+--------------+--------+---------------------------------------------------------+
| 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.            |
+--------------+--------+---------------------------------------------------------+

Atau untuk orang malas perintah buat tabel SQL untuk contoh ini:

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;

Layanan PHP

Implementasi ini sepenuhnya bergantung pada kebutuhan aplikasi Anda, Catatan: Ini adalah contoh bukan standar emas tentang cara membangun sistem notifikasi di PHP.

Model pemberitahuan

Ini adalah contoh model dasar dari notifikasi itu sendiri, tidak ada yang mewah hanya properti yang dibutuhkan dan metode abstrak messageForNotification dan messageForNotifications kami berharap diimplementasikan dalam berbagai jenis notifikasi.

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);
    }
}

Anda harus menambahkan konstruktor , getter , setter dan hal-hal semacam itu sendiri dengan gaya Anda sendiri, saya tidak akan menyediakan sistem Pemberitahuan yang siap pakai.

Jenis Pemberitahuan

Sekarang Anda dapat membuat Notification baru subkelas untuk setiap jenis. Contoh berikut ini akan menangani tindakan suka dari komentar:

  • Ray menyukai komentar Anda. (1 pemberitahuan)
  • John dan Jane menyukai komentar Anda. (2 pemberitahuan)
  • Jane, Johnny, James, dan Jenny menyukai komentar Anda. (4 pemberitahuan)
  • Jonny, James, dan 12 lainnya menyukai komentar Anda. (14 pemberitahuan)

Contoh implementasi:

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
    }
}

Manajer notifikasi

Untuk bekerja dengan notifikasi di dalam aplikasi Anda, buat sesuatu seperti pengelola notifikasi:

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 properti harus berisi logika dalam komunikasi langsung dengan backend data Anda dalam kasus contoh ini mysql.

Membuat notifikasi

Menggunakan mysql Pemicunya tidak salah, karena tidak ada solusi yang salah. Apa yang berhasil, berhasil.. Tapi saya sangat menyarankan untuk tidak membiarkan database menangani logika aplikasi.

Jadi di dalam pengelola notifikasi, Anda mungkin ingin melakukan sesuatu seperti ini:

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(),
        ]);
    }
}

Di belakang add metode notificationAdapter bisa menjadi perintah penyisipan mysql mentah. Menggunakan abstraksi adaptor ini memungkinkan Anda untuk beralih dengan mudah dari mysql ke database berbasis dokumen seperti mongodb yang masuk akal untuk sistem Notifikasi.

isDoublicate metode pada notificationAdapter sebaiknya cukup periksa apakah sudah ada notifikasi dengan recipient yang sama , sender , type dan reference .

Saya tidak bisa cukup menunjukkan bahwa ini hanya sebuah contoh. (Juga saya benar-benar harus mempersingkat langkah selanjutnya posting ini menjadi sangat panjang -.-)

Jadi dengan asumsi Anda memiliki semacam pengontrol dengan tindakan ketika seorang guru mengunggah pekerjaan rumah:

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);
    }
}

Akan membuat notifikasi untuk setiap siswa guru ketika dia mengunggah pekerjaan rumah baru.

Membaca notifikasi

Sekarang sampai pada bagian yang sulit. Masalah dengan pengelompokan di sisi PHP adalah Anda harus memuat semua pemberitahuan pengguna saat ini untuk mengelompokkannya dengan benar. Ini akan menjadi buruk, jika Anda hanya memiliki beberapa pengguna mungkin masih tidak ada masalah, tapi itu tidak membuatnya baik.

Solusi mudahnya adalah dengan membatasi jumlah notifikasi yang diminta dan hanya mengelompokkannya. Ini akan berfungsi dengan baik ketika tidak ada banyak notifikasi serupa (seperti 3-4 per 20). Tetapi katakanlah posting seorang pengguna / siswa mendapat sekitar seratus suka dan Anda hanya memilih 20 notifikasi terakhir. Pengguna kemudian hanya akan melihat bahwa 20 orang menyukai posnya juga yang akan menjadi satu-satunya pemberitahuannya.

Solusi "benar" akan mengelompokkan notifikasi yang sudah ada di database dan hanya memilih beberapa sampel per grup notifikasi. Daripada Anda hanya perlu memasukkan hitungan sebenarnya ke dalam pesan notifikasi Anda.

Anda mungkin tidak membaca teks di bawah ini, jadi izinkan saya melanjutkan dengan cuplikan:

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

Sekarang Anda tahu notifikasi apa yang harus ada untuk pengguna tertentu dan berapa banyak notifikasi yang ada di grup.

Dan sekarang bagian yang menyebalkan. Saya masih tidak dapat menemukan cara yang lebih baik untuk memilih sejumlah pemberitahuan terbatas untuk setiap grup tanpa melakukan kueri untuk setiap grup. Semua saran di sini sangat diharapkan.

Jadi saya melakukan sesuatu seperti:

$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;
}

Sekarang saya akan melanjutkan dengan asumsi bahwa notificationAdapter s get metode mengimplementasikan pengelompokan ini dan mengembalikan array seperti ini:

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

Karena kami selalu memiliki setidaknya satu notifikasi di grup kami dan pemesanan kami memilih Belum Dibaca dan Baru notifikasi kita bisa menggunakan notifikasi pertama sebagai contoh untuk rendering.

Jadi untuk dapat bekerja dengan notifikasi yang dikelompokkan ini, kita memerlukan objek baru:

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);
    }
}

Dan akhirnya kami benar-benar dapat menyatukan sebagian besar barang. Ini adalah bagaimana fungsi get pada NotificationManager mungkin terlihat seperti:

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;
}

Dan akhirnya benar-benar di dalam tindakan pengontrol yang mungkin:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Hasil MySQL sebagai daftar yang dipisahkan koma

  2. MySQL PHP - PILIH DI MANA id =array()?

  3. Pilih baris dari tabel MySQL di mana stempel waktu PHP lebih tua dari X

  4. Memeriksa tabel untuk tumpang tindih waktu?

  5. tabel mysqldump tanpa membuang kunci utama