Nå, dette spørgsmål er 9 måneder gammelt, så jeg er ikke sikker på, om OP stadig mangler et svar, men på grund af de mange synspunkter og den velsmagende overflod vil jeg også gerne tilføje min sennep (tysk ordsprog..).
I dette indlæg vil jeg forsøge at lave et enkelt forklaret eksempel på, hvordan man begynder at bygge et notifikationssystem.
Rediger: Nå ok, det her blev langt, meget længere, end jeg havde forventet. Jeg blev virkelig træt til sidst, undskyld.
WTLDR;
Spørgsmål 1: have et flag på hver notifikation.
Spørgsmål 2: Gem stadig hver notifikation som en enkelt post i din database og grupper dem, når de bliver anmodet om.
Struktur
Jeg går ud fra, at meddelelserne vil se nogenlunde sådan ud:
+------------------------------------------------ --+| ▣ James har uploadet nyt hjemmearbejde:matematik 1+1 |+------------------------------------------------ --------+| ▣ Jane og John kunne lide din kommentar:Jeg er... | +----------------------------------------------------+| ▢ Skolen er lukket på uafhængighedsdagen. |+----------------------------------------------------+
Bag gardinerne kunne dette se sådan ud:
+--------+------------+--------+------------- ----+---------------------------------------------------+| ulæst | modtager | afsender | type | reference |+--------+-----------+--------+---------------- +---------------------------------------------------+| sandt | mig | James | hjemmearbejde.skabe | Matematik 1 + 1 |+--------+------------+--------+------------- ---+---------------------------------------------------+| sandt | mig | Jane | comment.like | Jeg er træt af skolen |+--------+------------+--------+-------------- ---+---------------------------------------------------+| sandt | mig | John | comment.like | Jeg er træt af skolen |+--------+------------+--------+-------------- ---+---------------------------------------------------+| falsk | mig | system | besked | Skolen holder lukket på uafhængighedsdagen. |+--------+-----------+--------+----------------+ --------------------------------------------------+
Bemærk: Jeg anbefaler ikke at gruppere meddelelserne inde i databasen, gør det på runtime, dette holder tingene meget mere fleksible.
- Ulæst
Hver meddelelse skal have et flag for at angive, om modtageren allerede har åbnet meddelelsen.
- Modtager
Definerer, hvem der modtager meddelelsen.
- Afsender
Definerer, hvem der udløste meddelelsen.
- Type
I stedet for at have hver besked i almindelig tekst i din database, skal du oprette typer. På denne måde kan du oprette specielle handlere til forskellige meddelelsestyper inde i din backend. Vil reducere mængden af data gemt i din database og giver din endnu mere fleksibilitet, muliggør nem oversættelse af notifikationer, ændringer af tidligere beskeder osv.
- Reference
De fleste meddelelser vil have en reference til en post i din database eller dit program.
Hvert system, jeg har arbejdet på, havde en simpel 1 til 1 referenceforhold på en meddelelse, har du muligvis et 1 til n husk på, at jeg vil fortsætte mit eksempel med 1:1. Dette betyder også, at jeg ikke behøver et felt, der definerer, hvilken type objekt der henvises til, fordi dette er defineret af meddelelsestypen.
SQL-tabel
Når vi nu definerer en rigtig tabelstruktur for SQL, kommer vi til et par beslutninger med hensyn til databasedesignet. Jeg vil gå med den enkleste løsning, som vil se sådan ud:
+--------------+--------+------------------------ --------------------------------------------+| kolonne | type | beskrivelse |+--------------+--------+----------------------------- ----------------------------------+| id | int | Primær nøgle |+--------------+--------+---------------------- -----------------------------------+| modtager_id | int | Modtagerens bruger-id. |+-------------+--------+------------------------ ----------------------------------+| sender_id | int | Afsenderens bruger-id. |+-------------+--------+------------------------ ----------------------------------+| ulæst | bool | Markér, hvis modtageren allerede har læst meddelelsen |+--------------+--------+--------------- ------------------------------------------+| type | streng | Underretningstypen. |+-------------+--------+------------------------ ----------------------------------+| parametre | række | Yderligere data til at gengive forskellige meddelelsestyper. |+-------------+--------+------------------------ ----------------------------------+| reference_id | int | Den primære nøgle for det refererende objekt. |+-------------+--------+------------------------ ----------------------------------+| oprettet_ved | int | Tidsstempel for meddelelsens oprettelsesdato. |+-------------+--------+------------------------ ----------------------------------+
Eller for de dovne mennesker, kommandoen SQL create table for dette eksempel:
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-tjeneste
Denne implementering afhænger fuldstændigt af din applikations behov, Bemærk: Dette er et eksempel, der ikke er den gyldne standard for, hvordan man bygger et meddelelsessystem i PHP.
Meddelelsesmodel
Dette er et eksempel på en basismodel af selve meddelelsen, intet fancy, bare de nødvendige egenskaber og de abstrakte metoder messageForNotification
og messageForNotifications
vi forventede at blive implementeret i de forskellige notifikationstyper.
abstract class Notification{ protected $recipient; beskyttet $sender; beskyttet $ulæst; beskyttet $type; beskyttede $parametre; beskyttet $referenceId; beskyttet $createdAt; /** * Meddelelsesgeneratorer, der skal defineres i underklasser */ public function messageForNotification(Notification $notification) :string; public function messageForNotifications(array $notifications):string; /** * Generer besked om den aktuelle meddelelse. */ public function message() :string { return $this->messageForNotification($this); }}
Du bliver nødt til at tilføje en konstruktør , getters , sættere og den slags ting for dig selv i din egen stil, jeg har ikke tænkt mig at levere et klar til brug meddelelsessystem.
Meddelelsestyper
Nu kan du oprette en ny Meddelelse
underklasse for hver type. Dette følgende eksempel ville håndtere like-handlingen af en kommentar:
- Ray har kunne lide din kommentar. (1 meddelelse)
- John og Jane kunne lide din kommentar. (2 meddelelser)
- Jane, Johnny, James og Jenny kunne lide din kommentar. (4 meddelelser)
- Jonny, James og 12 andre kunne lide din kommentar. (14 meddelelser)
Eksempel på implementering:
namespace Notification\Comment;class CommentLikedNotification udvider \Notification{ /** * Generer en besked til en enkelt notifikation * * @param Notification $notification * @return string */ public function messageForNotification(Notification $notification) :string { return $this->sender->getName() . 'har kunne lide din kommentar:' . substr($this->reference->tekst, 0, 10) . '...'; } /** * Generer en besked til flere meddelelser * * @param array $notifications * @return string */ public function messageForNotifications(array $notifications, int $realCount =0) :string { if ($realCount ===0 ) { $realCount =count($notifications); } // når der er to if ($realCount ===2) { $names =$this->messageForTwoNotifications($notifications); } // mindre end fem elseif ($realCount <5) { $names =$this->messageForManyNotifications($notifications); } // til mange andre { $names =$this->messageForManyManyNotifications($notifications, $realCount); } returner $navne. ' kunne lide din kommentar:' . substr($this->reference->tekst, 0, 10) . '...'; } /** * Generer en besked til to meddelelser * * John og Jane har kunne lide din kommentar. * * @param array $notifications * @return string */ protected function messageForTwoNotifications(array $notifications) :string { list($first, $second) =$notifications; returner $first->getName() . 'og'. $second->getName(); // John and Jane } /** * Generer en besked mange meddelelser * * Jane, Johnny, James og Jenny har kunne lide din kommentar. * * @param array $notifications * @return string */ protected function messageForManyNotifications(array $notifications) :string { $last =array_pop($notifications); foreach($notifications as $notification) { $names .=$notification->getName() . ', '; } returner substr($navne, 0, -2) . 'og'. $last->getName(); // Jane, Johnny, James og Jenny } /** * Generer en besked til mange mange notifikationer * * Jonny, James og 12 andre har kunne lide din kommentar. * * @param array $notifications * @return string */ protected function messageForManyManyNotifications(array $notifications, int $realCount) :string { list($first, $second) =array_slice($notifications, 0, 2); returner $first->getName() . ','. $second->getName() . 'og'. $realCount . 'andre'; // Jonny, James og 12 andre }}
Meddelelsesadministrator
For at arbejde med dine meddelelser inde i din applikation skal du oprette noget som en meddelelsesadministrator:
klasse NotificationManager{ protected $notificationAdapter; public function add(Meddelelse $meddelelse); offentlig funktion markRead(matrix $meddelelser); public function get(Bruger $user, $limit =20, $offset =0):array;}
notifikationsadapteren
egenskaben skal indeholde logikken i direkte kommunikation med din databackend i tilfælde af dette eksempel mysql.
Oprettelse af meddelelser
Brug af mysql
triggere er ikke forkert, for der er ingen forkert løsning. Hvad der virker, virker... Men jeg anbefaler på det kraftigste ikke at lade databasen håndtere applikationslogik.
Så inde i notifikationsadministratoren vil du måske gøre noget som dette:
public function add(Notification $notification){// Gem kun notifikationen, hvis der ikke findes nogen mulig duplikat. 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' => tid(), ]); }}
Bag add
metode til notificationAdapter
kan være en rå mysql insert-kommando. Ved at bruge denne adapterabstraktion kan du nemt skifte fra mysql til en dokumentbaseret database som mongodb hvilket ville give mening for et meddelelsessystem.
isDoublicate
metode på notificationAdapter
skal blot tjekke, om der allerede er en notifikation med den samme modtager
, afsender
, type
og reference
.
Jeg kan ikke påpege nok, at dette kun er et eksempel. (Jeg er også virkelig nødt til at forkorte de næste trin, dette indlæg er ved at blive latterligt langt -.-)
Så forudsat at du har en form for controller med en handling, når en lærer uploader lektier:
funktion uploadHomeworkAction(Request $request){// håndtere lektierne og få dem gemt i var $homework. // hvordan du håndterer dine tjenester er op til dig... $notificationManager =ny NotificationManager; foreach($homework->teacher->students as $student) { $notification =new Notification\Homework\HomeworkUploadedNotification; $notification->sender =$homework->lærer; $notification->recipient =$student; $notification->reference =$hjemmearbejde; // send notifikationen $notificationManager->add($notification); }}
Opretter en notifikation til hver lærers elev, når han uploader et nyt hjemmearbejde.
Læsning af meddelelserne
Nu kommer den svære del. Problemet med gruppering på PHP-siden er, at du bliver nødt til at indlæse alle meddelelser fra den aktuelle bruger for at gruppere dem korrekt. Dette ville være dårligt, godt hvis du kun har nogle få brugere, ville det sandsynligvis stadig ikke være noget problem, men det gør det ikke godt.
Den nemme løsning er blot at begrænse antallet af anmodede meddelelser og kun gruppere disse. Dette vil fungere fint, når der ikke er mange lignende meddelelser (som 3-4 pr. 20). Men lad os sige, at indlægget fra en bruger/elev får omkring hundrede likes, og at du kun vælger de sidste 20 notifikationer. Brugeren vil så kun se, at 20 personer kunne lide hans opslag, også det ville være hans eneste notifikation.
En "korrekt" løsning ville være at gruppere de meddelelser, der allerede er i databasen, og kun vælge nogle prøver pr. meddelelsesgruppe. Så skulle du bare indsætte det rigtige antal i dine meddelelser.
Du har sandsynligvis ikke læst teksten nedenfor, så lad mig fortsætte med et uddrag:
vælg *, count(*) som tæller fra notifikationer, hvor recipient_id =1group by `type`, `reference_id`order by created_at desc, unread desclimit 20
Nu ved du, hvilke notifikationer der skal findes for den givne bruger, og hvor mange notifikationer gruppen indeholder.
Og nu den lorte del. Jeg kunne stadig ikke finde ud af en bedre måde at vælge et begrænset antal meddelelser for hver gruppe uden at lave en forespørgsel for hver gruppe. Alle forslag her er meget velkomne.
Så jeg gør noget som:
$notifcationGroups =[];foreach($results as $notification){ $notifcationGroup =['count' => $notification['count']]; // når gruppen kun indeholder ét element, behøver vi ikke // at vælge dets børn if ($notification['count'] ==1) { $notifcationGroup['items'] =[$notification]; } else { // eksempel med 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;}
Jeg vil nu fortsætte med at antage, at notificationAdapter
s get
metode implementerer denne gruppering og returnerer et array som dette:
[ { count:12, items:[Note1, Note2, Note3, Note4, Note5] }, { count:1, items:[Note1] }, { count:3, items:[Note1, Note2 , Note3] }]
Fordi vi altid har mindst én notifikation i vores gruppe, og vores bestilling foretrækker Ulæst og Ny meddelelser, vi kan bare bruge den første meddelelse som et eksempel til gengivelse.
Så for at kunne arbejde med disse grupperede meddelelser har vi brug for et nyt objekt:
class NotificationGroup{ protected $notifications; beskyttet $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); } // videresend alle andre opkald til den første offentlige notifikationsfunktion __call($method, $arguments) { return call_user_func_array([$this->notifications[0], $method], $arguments); }}
Og endelig kan vi faktisk sætte det meste sammen. Sådan får funktionen på NotificationManager
kan se sådan ud:
offentlig funktion get(Bruger $user, $limit =20, $offset =0):array{ $groups =[]; foreach($this->notificationAdapter->get($user->getId(), $limit, $offset) som $group) { $groups[] =new NotificationGroup($group['notifications'], $group[' tælle']); } returner $gorups;}
Og virkelig endelig inde i en mulig controller-handling:
public function viewNotificationsAction(Request $request){ $notificationManager =new NotificationManager; foreach($notifications =$notificationManager->get($this->getUser()) som $group) { echo $group->ulæst . ' | '. $group->message() . '-'. $group->createdAt() . "\n"; } // marker dem som læst $notificationManager->markRead($notifications);}