Problem
Jeg har meldinger i systemet sendt mellom flere personer som en gruppechat. Hver gang noen går for å laste inn meldinger (åpner innboksen), må jeg få disse meldingene flagget som lest. Jeg har ikke en veltalende modell for Direct_Message_read_at Pivot -tabellen, og jeg bruker en klasse som innkapsler DB Laravel -klasse for å skrive tilpasset MySQL -spørring for å gjøre dette.
Problemet mitt er, hvordan forhindrer jeg dupliserte oppføringer hvis noen åpner meldingstråden 10 ganger, og få den oppdaterte_at tidsstempel endres hver gang de leser meldingen? (Siden de åpner den samme meldingstråden flere ganger)
Løsning
For å hjelpe med oppsettet av denne løsningen, la oss først vise hvordan vi lager denne tabellen ved hjelp av Laravel Migration:
Før pivoten vil vi opprette en meldingstabell for å lagre alle meldingene fra folk. Etter det lager vi pivottabellen.
Skjema :: create ('Direct_Message_read_at', funksjon (blåkopi $ tabell)
$ tabell-> trinn ('id');
$ tabell-> heltall ('message_id')-> usignert ()-> nullable ();
$ tabell-> utenlandsk ('message_id')-> Referanser ('id')-> på ('Direct_Messages')-> ondelete ('Cascade');
$ tabell-> heltall ('user_id')-> usignert ()-> nullable ();
$ tabell-> utenlandske ('user_id')-> Referanser ('id')-> på ('brukere')-> ondelete ('cascade');
$ tabell-> heltall ('organisasjon_id')-> usignert ()-> nullable ();
$ tabell-> utenlandske ('Organization_id')-> Referanser ('id')-> på ('organisasjoner')-> ondelete ('cascade');
$ tabell-> tidsstempler ();
$ tabell-> unik (['message_id', 'user_id', 'organisasjon_id']); // dette er veldig viktig for
Forhindre dupliserte oppføringer av samme person
);
Nå ønsker vi å lage en begivenhet og en lytter som skal behandle de lastede meldingene.
Se for deg at du har en klasse som er ansvarlig for å laste inn alle meldingene dine (når du åpner innboksen)
Offentlig funksjon LoadMessages ()
$ thread_messages = DirectMessage :: all ();
$ message_ids = $ this-> removeemymessages ($ thread_messages)
hendelse (ny messagesread ($ messages_ids));
beskyttet funksjon fjerne -messer ($ meldinger)
$ message_ids = [];
// ganske enkelt filtrere ut alle meldingene som sendes av deg ved å bruke 'hvor (' avsender_id ',
Auth ()-> bruker ()-> id)-Bruk din egen kodelogikk for å gjøre det
Returner $ Message_ids;
Nå inne i MessagesRead kan du definere disse og gi dem til lytteren
Klassemeldinger
Bruk utsendbare, interaktswithsockets, serialisesmodeller;
public $ messages_ids = [], $ user_id, $ organisasjon_id;
/**
* Opprett en ny hendelsesinstans.
*
* @return void
*/
offentlig funksjon __construct ($ message_ids = [])
$ this-> messages_ids = $ message_ids;
$ this-> user_id = autor ()-> bruker ()-> id;
$ this-> Organization_id = autor ()-> bruker ()-> organisasjon_id;
/**
* Få kanalene arrangementet skal sendes videre.
*
* @return \ Illuminate \ Broadcasting \ Channel | Array
*/
offentlig funksjon Broadcaston ()
returnere nytt privatkanal ('kanalnavn');
Inne i lytteren som du tidligere har definert i EventServiceProvider, kan du ringe klassen din for å behandle oppdateringen av Pivot -tabellen
Klasse markeringsAsRead
/**
* Opprett arrangementets lytter.
*
* @return void
*/
offentlig funksjon __konstruksjon ()
//
/**
* Håndter arrangementet.
*
* @param messagesRead $ arrangement
* @return void
*/
Public Function Handle (MessageRead $ Event)
$ message_ids = $ event-> messages_ids;
$ user_id = $ event-> user_id;
$ organisasjon_id = $ Event-> Organization_id;
(New CreateRectMessageReadIndicator (New DB))-> Utfør ($ Message_ids, $ user_id,
$ organisasjon_id);
Og til slutt kommer vi nærmere slutten. Alt vi trenger å gjøre nå er å faktisk se på MySQL -spørringen
Klasse CreateRectMessageReadIndicator
beskyttet $ db;
funksjon __construct (db $ db)
$ this-> db = $ db;
/**
* Bygg og returner velgklausulen for spørringen
*
* @return -streng
*/
public Function Execute ($ message_ids = [], $ user_id, $ organisasjon_id)
if (count ($ message_ids) <= 0)
return falsk;
$ CATED_AT = DATO ('Y-M-D H: I: S');
$ oppdaterte_at = dato ('y-m-d h: i: s');
$ parametere = [];
foreach ($ message_ids as $ message_id)
array_push ($ parametere, "($ message_id, $ user_id, $ organisasjon_id,
'$ CATED_AT') ");
$ parameters_string = implode (",", $ parametere);
$ spørring = "
Sett inn Direct_Message_read_at (Message_id, user_id, organisasjon_id,
opprettet_at)
Verdier
$ parameters_string
På duplikat nøkkeloppdatering oppdaterte_at = "$ oppdaterte_at";
";
$ this-> db :: velg ($ spørring);
Så det som nettopp skjedde her. I utgangspunktet merket vi Message_id, user_id og organisasjon_id som den unike kombinasjonen. I tilfelle den samme brukeren_id som tilhører samme organisasjonsorganisasjon_id åpner den samme meldingen fra noen som har den meldingen_id, vil den kaste MySQL dupliseringsfeil.
Når du setter inn en ny rad i en tabell hvis raden forårsaker en duplikat i unik indeks eller primærnøkkel, vil MySQL utstede en feil.
Imidlertid, hvis du spesifiserer alternativet for duplikat nøkkeloppdatering i innsatserklæringen, vil MySQL oppdatere den eksisterende raden med de nye verdiene i stedet.
https: // www.mysqltutorial.org/mysql-Insert-or-update-on-duplicate-key-update/
La meg dele noen få skjermbilder.
Den første meldingen som leses:
Sett inn DIRECT_MESSAGE_READ_AT (Message_id, user_id, organisasjon_id, opprettet_at)
Verdier
(75, 3, 1, '2020-01-16 15:00:00')
På duplikat nøkkeloppdatering oppdatert_at = "2020-01-17 22:00:00"
Den vil produsere denne oppføringen i databasen:
Så kommer du tilbake og leser den samme meldingen i morgen, det vil føre til at bare den oppdaterte_at -kolonnen blir oppdatert:
På denne måten vet du når meldingen ble sett for første gang, og når var siste gang da meldingen ble lest.