Fino ad ora abbiamo preparato l’ambiente necessario per iniziare lo sviluppo del progetto. Ora è tempo di iniziare a implementare il modello alla base della chat. Per motivi di semplicità useremo un modello molto rudimentale. Laravel ci ha già fornito un modello per l’utente, dandoci anche del codice già funzionante per la procedura di autenticazione e registrazione. Trattandosi di una chat avremo bisogno di un modello per i messaggi scambiati tra i vari utenti.

Chat Laravel React e Pusher parte 1

Spesso può essere più semplice strutturare un database direttamente all’interno di un tool grafico, come può essere phpmyadmin  o SequelPro, o ci troviamo a dover importare un database già realizzato all’interno di un progetto Laravel. Tuttavia riscrivere ogni singolo modello può diventare un processo tedioso e molto incline a errori.

Per venire incontro a situazioni del genere esiste un tool che abbiamo installato nella fase precedente Eloquent Model Generator. Questo tool ci permette di generare modelli basati sulle tabelle specificate. Creiamo quindi la tabella message all’interno del nostro database.

 

CREATE TABLE `message` (

`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,

`from_id` bigint(20) unsigned NOT NULL,

`to_id` bigint(20) unsigned NOT NULL,

`text` text COLLATE utf8mb4_unicode_ci NOT NULL,

`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,

`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (`id`),

KEY `fk_from_user` (`from_id`),

KEY `fk_to_user` (`to_id`),

CONSTRAINT `fk_from_user` FOREIGN KEY (`from_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,

CONSTRAINT `fk_to_user` FOREIGN KEY (`to_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

 

Assegnamo un id autoincrementale a ciascun messaggio e gli assegnamo il tipo BIGINT con una lunghezza di 20 (come ha fatto Laravel in automatico per la tabella users). Associamo un mittente e un ricevente (from_id, to_id) dello stesso tipo dell’id della tabella users (BIGINT 20). Associamo una chiave esterna a ciascuno dei due campi, per renderli dipendenti dall’esistenza dell’utente che ha inviato o ricevuto il messaggio. Una colonna per contenere il testo del messaggio text e, infine, due campi di tipo TIMESTAMP per contenere la data di creazione e modifica del messaggio. Notate come abbiamo deciso di utilizzare lo stesso naming di Laravel per le ultime du colonne per poter approfittare del casting che Laravel applica di default ai campi così nominati.

 

Andiamo a terminale e, nella cartella principale del progetto digitiamo il comando

 

php artisan krlove:generate:model Message –table-name=message

 

Una volta completata l’esecuzione del comando, nella cartella app del progetto troveremo un nuovo file Message.php. Un veloce sguardo al file e noteremo che contiene due errori. Il tool che abbiamo utilizzato ha generato, giustamente, due relazioni sul modello, tutte e due di tipo belongsTo.

Le due relazioni però hanno la stessa signature: user(). Esse sono state create come conseguenza delle due chiavi esterne che abbiamo generato sulla tabella message. Concettualmente sono corrette, ma modifichiamo ora le signature

 

public function from()

{

return $this->belongsTo(‘App\User’, ‘from_id’);

}

 

e

 

public function to()

{

return $this->belongsTo(‘App\User’, ‘to_id’);

}

 

Vogliamo che i messaggi degli utenti siano criptati all’interno del nostro database, per garantire uno strato di sicurezza in più. Per rendere trasparente il processo di codifica e decodifica dei messaggi utilizzeremo i Mutators e Accessors che Laravel ci fornisce. All’interno del file Message.php inseriamo due nuove funzioni pubbliche.

 

public function getTextAttribute($value)

{

return decrypt($value);

}

public function setTextAttribute($value)

{

$this->attributes[‘text’] = encrypt($value);

}

 

Quando andremo a manipolare in lettura o scrittura la proprietà text di un’istanza della classe Message il valore passato o richiesto verrà sempre prima codificato o decodificato.

Implementiamo ora una funzione che aggiunga un messaggio al database. Apriamo il file app/Http/Controllers/HomeController.php e aggiungiamo la funzione addMessage e le direttive necessarie per poter utilizzare le classi dei modelli.

 

use App\Message;

use App\User;

 

public function addMessage(Request $request, User $from, User $to)

{

$newMessage = new Message;

 

$newMessage->from_id = $from->id;

$newMessage->to_id = $to->id;

$newMessage->text = $request->text;

 

$newMessage->save();

 

return $newMessage->toJson();

}

 

Usiamo il binding di Laravel per il mittente e il ricevente del messaggio, mentre il testo del messaggio stesso si troverà nel body della richiesta, che sarà di tipo POST.

Questa funzione verrà chiamata da una richiesta asincrona all’interno dell’app React, di conseguenza andremo a implementare la route che la richiamerà nel file routes/api.php

 

            Route::post(‘message/{from}/{to}’, ‘HomeController@addMessage’);

 

Disabilitiamo per ora l’autenticazione all’interno di HomeController.php

 

public function __construct()

{

// $this->middleware(‘auth’);

}

 

Possiamo ora utilizzare Postman per eseguire una richiesta e verificare che tutto funzioni correttamente. Aggiungiamo ora anche una funzione per recuperare tutti i messaggi tra due utenti e la route corrispondente.

In HomeController.php

 

            public function messages(Request $request, User $from, User $to) {

$messages = Message::where(function($query) use($from, $to) {

$query->where(‘from_id’, $from->id)->where(‘to_id’, $to->id);

})->orWhere(function($query) use($from, $to) {

$query->where(‘from_id’, $to->id)->where(‘to_id’, $from->id);

})->get();

return $messages->toJson();

}

 

 

e in api.php

 

 

            Route::get(‘/messages/{from}/{to}’, ‘HomeController@messages’);

 

 

Eseguendo le richieste in Postman noteremo che il testo ci viene sempre restituito in chiaro, mentre se andiamo a guardare il valore delle righe nel database vedremo che il testo è criptato.

La chat che vogliamo sviluppare deve avere anche un sistema di prevenzione dell’invio di messaggi che potrebbero avere un contenuto ‘poco educato’. A questo scopo andremo a implementare un semplice Middleware, che, nel caso la chiamata sia di aggiunta ad un messaggio, ne verificherà il contenuto, e non propagherà la richiesta nel caso il testo contenga determinati termini.

Nella cartella app/Http/Middleware creiamo il Middleware MessageValidator.php

 

<?php

 

namespace App\Http\Middleware;

 

use Closure;

 

class MessageValidator

{

static $offensiveWords = [

‘parola1’,

‘parola2’,

‘parola3’

];

public function handle($request, Closure $next)

{

if ($request->is(‘*/message/*’) && $request->isMethod(‘post’)) {

$messageText = $request->text;

for ($i = 0; $i < count(MessageValidator::$offensiveWords); $i++) {

$currentWord = MessageValidator::$offensiveWords[$i];

if (strpos(strtolower($messageText), strtolower($currentWord)) !== FALSE

) {

return response(json_encode([‘status’ => ‘KO’, ‘error’ =>                                                ‘Offensive word(s) detected in your message!’]));

}

}

 

return $next($request);

} else {

return $next($request);

}

}

}

 

Abbiamo dichiarato un array statico che conterrà tutte le parole considerate non appropriate, mentre nella funzione handle, che viene richiamata dal sistema di routing di Laravel, dopo esserci assicurati che la richiesta sia di tipo POST e che stia per aggiungere un messaggio, facciamo una semplice verifica sulla stringa del messaggio per assicurarci che non siano contenute alcune delle parole della lista definita in alto.

Nel caso la verifica trovi una delle parole all’interno del messaggio, la richiesta non verrà propagata e verrà restituito un messaggio di errore. Altrimenti se la chiamata differisce da quella di nostro interesse, propagherà la richiesta restituendola al sistema di routing di Laravel.

Inseriamo ora il Middleware creato nella catena dei Middleware già installati di default da Laravel. Andiamo nel file app/Http/Kernel.php e nell’array routeMiddleware inseriamo la seguente riga

 

 

‘validate’ => \App\Http\Middleware\MessageValidator::class,

 

 

All’interno dell’array middlewareGroups, nell’array della chiave api inseriamo la stringa ‘validate’.

Per adesso ci fermiamo qui, e ci rivediamo per la terza puntata di “Realizzare una chat con Laravel e React” la prossima settimana…  speriamo vi stia piacendo questa piccola rubrica a puntate, stay super tuned LaraMind non vede l’ora di fornire altri contenuti gratuiti e utili alla tua carriera di developer!

Per qualsiasi domanda scrivici a   amministrazione@laramind.com

Chat Laravel React e Pusher parte 3