Mysql
 sql >> डेटाबेस >  >> RDS >> Mysql

Php और mysql का उपयोग कर अधिसूचना प्रणाली

वैसे यह प्रश्न 9 महीने पुराना है इसलिए मुझे यकीन नहीं है कि ओपी को अभी भी उत्तर की आवश्यकता है, लेकिन कई विचारों और स्वादिष्ट इनाम के कारण मैं अपनी सरसों (जर्मन कहावत ..) भी जोड़ना चाहूंगा।

इस पोस्ट में मैं एक सरल समझाया उदाहरण बनाने की कोशिश करूंगा कि अधिसूचना प्रणाली का निर्माण कैसे शुरू किया जाए।

संपादित करें: ठीक है, यह रास्ता, रास्ता, जितना मैंने उम्मीद की थी, उससे कहीं अधिक लंबा हो गया। मैं अंत में वास्तव में थक गया, मुझे क्षमा करें।

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 से n . हो सकता है ध्यान रखें कि मैं अपना उदाहरण 1:1 के साथ जारी रखूंगा। इसका अर्थ यह भी है कि मुझे किसी फ़ील्ड की आवश्यकता नहीं है जो परिभाषित करता है कि किस प्रकार की वस्तु का संदर्भ दिया गया है क्योंकि यह अधिसूचना प्रकार द्वारा परिभाषित किया गया है।

एसक्यूएल टेबल

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

या आलसी लोगों के लिए एसक्यूएल क्रिएट टेबल कमांड इस उदाहरण के लिए:

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 सेवा

यह कार्यान्वयन पूरी तरह से आपके आवेदन की आवश्यकताओं पर निर्भर करता है, नोट: यह एक उदाहरण है न कि पीएचपी में अधिसूचना प्रणाली बनाने का सुनहरा मानक।

अधिसूचना मॉडल

यह अधिसूचना का एक उदाहरण आधार मॉडल है, केवल आवश्यक गुणों और सार विधियों 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);
    }
}

आपको एक कन्स्ट्रक्टर जोड़ना होगा , प्राप्तकर्ता , सेटर्स और उस तरह की चीजें अपने आप में अपनी शैली में, मैं अधिसूचना प्रणाली का उपयोग करने के लिए तैयार नहीं होने जा रहा हूं।

सूचना प्रकार

अब आप एक नया Notification बना सकते हैं हर प्रकार के लिए उपवर्ग। यह निम्नलिखित उदाहरण समान कार्रवाई को संभालेगा एक टिप्पणी का:

  • रे ने आपकी टिप्पणी पसंद की है। (1 अधिसूचना)
  • जॉन और जेन को आपकी टिप्पणी पसंद आई। (2 सूचनाएं)
  • जेन, जॉनी, जेम्स और जेनी को आपकी टिप्पणी पसंद आई। (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 . के पीछे notificationAdapter . की विधि एक कच्चा mysql इन्सर्ट कमांड हो सकता है। इस एडेप्टर एब्स्ट्रैक्शन का उपयोग करने से आप आसानी से mysql से दस्तावेज़ आधारित डेटाबेस जैसे mongodb . पर स्विच कर सकते हैं जो एक अधिसूचना प्रणाली के लिए समझ में आता है।

isDoublicate notificationAdapter . पर विधि बस यह जांचना चाहिए कि क्या पहले से ही समान 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 पक्ष पर समूहीकरण के साथ समस्या यह है कि आपको सभी . को लोड करना होगा वर्तमान उपयोगकर्ता की सूचनाएं उन्हें सही ढंग से समूहित करने के लिए। यह बुरा होगा, ठीक है यदि आपके पास केवल कुछ उपयोगकर्ता हैं तो शायद यह अभी भी कोई समस्या नहीं होगी, लेकिन इससे यह अच्छा नहीं होता है।

इसका आसान समाधान केवल अनुरोधित सूचनाओं की संख्या को सीमित करना और उन्हें केवल समूहबद्ध करना है। यह तब ठीक काम करेगा जब कई समान सूचनाएं नहीं होंगी (जैसे 3-4 प्रति 20)। लेकिन मान लें कि किसी उपयोगकर्ता/छात्र की पोस्ट को लगभग सौ लाइक्स मिलते हैं और आप केवल अंतिम 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;
}

अब मैं यह मानकर चलता रहूंगा कि notificationAdapter रों get मेथड इस ग्रुपिंग को लागू करता है और इस तरह से एक ऐरे देता है:

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

क्योंकि हमारे समूह में हमेशा कम से कम एक सूचना होती है और हमारा आदेश अपठित . को प्राथमिकता देता है और नया सूचनाएँ हम केवल पहली सूचना को प्रतिपादन के लिए एक नमूने के रूप में उपयोग कर सकते हैं।

इसलिए इन समूहीकृत सूचनाओं के साथ काम करने में सक्षम होने के लिए हमें एक नई वस्तु की आवश्यकता है:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. किसी शर्त के साथ पंक्तियों की गिनती करते समय मुझे MySQL में OR NULL की आवश्यकता क्यों है?

  2. MySQL में तालिका टिप्पणी की लंबाई

  3. Yii CDbCriteria में mysql सबक्वेरी को कैसे बदलें?

  4. पीके या आईडी या mysql में अद्वितीय कॉलम के बिना तालिका से डुप्लिकेट किए गए रिकॉर्ड हटाएं

  5. MySql में पदानुक्रमित डेटा