Essenzialmente una wish list è un array di ID di prodotti collegati ad un profilo utente. Per crearla dobbiamo aggiungere un nuovo modello avente la seguente struttura.
namespace App;
use Illuminate\Database\Eloquent\Model;
class WishList extends Model
{
protected $table = 'wish_lists';
protected $primaryKey = 'id';
public $incrementing = true;
protected $fillable = ['customer_id', 'product_id'];
}
Ciascun record associa un ID di un profilo cliente con l'ID di un prodotto specifico. A questo punto dobbiamo modificare anche il modello del profilo cliente aggiungendo un metodo che crei la relazione one-to-many con il modello della wish list.
public function wish_list()
{
return $this->hasMany('App\WishList');
}
Visualizzare i record della wish list
Avendo collegato un account ad una wish list abbiamo a disposizione una lista di ID di prodotti che possiamo riunire in un unico array per reperire i modelli dei prodotti corrispondenti.
Per farlo, modifichiamo il metodo del nostro controller che gestisce il profilo dei clienti.
public function profile()
{
$customer = Customer::find(session()->get('customer_id'));
$wish_list = $customer->wish_list;
$wish_list_product_ids = [];
$countries = Country::all();
$provinces = Province::all();
$cities = Municipality::all();
foreach($wish_list as $item) {
$wish_list_product_ids[] = $item->product_id;
}
$wish_list_products = Product::whereIn('id', $wish_list_product_ids)->get();
return view('profile', [
'title' => 'Profile | PHP E-commerce',
'customer' => $customer,
'wish_list_products' => $wish_list_products,
'countries' => $countries,
'provinces' => $provinces,
'cities' => $cities
]);
}
Il metodo Eloquent whereIn()
seleziona solo quei modelli la cui chiave è compresa nell'array di valori passato come secondo argomento.
Quindi aggiungiamo l'elenco dei prodotti nel profilo del cliente.
<div class="tab-pane fade" id="wish-list" role="tabpanel" aria-labelledby="wish-list-tab">
@if(count($wish_list_products) > 0)
<table class="table table-bordered table-striped">
<tbody>
@foreach($wish_list_products as $product)
<tr>
<td>
<a href="{{ url('/') }}/prodotti/{{ $product['slug'] }}" target="_blank">{{ $product['title'] }}</a>
</td>
<td>
<a href="#" class="text-danger remove-from-wish-list" data-product="{{ $product['id'] }}" data-customer="{{ session('customer_id') }}">
<i class="fa fa-trash"></i>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<p class="alert alert-info mt-lg-5">You currently don't have any products in your wish list.</p>
@endif
</div>
L'aggiunta e la rimozione dei prodotti della wish list è ovviamente permessa solo agli utenti che hanno effettuato il login e che sono autenticati sul nostro sito.
Inserimento dei record nella wish list
Per l'aggiunta dobbiamo creare un link che gestiremo con AJAX in cui saranno presenti due dati fondamentali: l'ID del prodotto e l'ID del cliente attualmente collegato. Nelle view possiamo inserire il seguente blocco di codice:
@if(session('logged_in'))
<a href="#" class="btn btn-outline-primary add-to-wish-list mr-3" data-product="{{ $product['id'] }}" data-customer="{{ session('customer_id') }}">
<i class="fa fa-heart"></i> Add to wish list
</a>
@endif
A questo punto dobbiamo creare un metodo AJAX nel nostro controller specifico.
public function addToWishList(Request $request)
{
$customer_id = $request->get('customer_id');
$product_id = $request->get('product_id');
$existing_entry = WishList::where([
['customer_id', '=', $customer_id],
['product_id', '=', $product_id],
])->exists();
if($existing_entry) {
return response()->json(['error' => 'This product is already in your wish list.']);
}
$new_entry = new WishList([
'customer_id' => $customer_id,
'product_id' => $product_id
]);
$new_entry->save();
return response()->json(['success' => 'Product added to your wish list.']);
}
Se il prodotto non è già presente nella wish list del cliente creiamo una nuova istanza del modello WishList
e la salviamo con l'ID del prodotto e del cliente. In caso contrario informiamo comunque l'utente che il prodotto è già nella sua wish list. In questo modo evitiamo di avere valori duplicati.
Lato frontend possiamo gestire la richiesta AJAX come segue:
$( ".add-to-wish-list" ).click(function() {
var $a = $( this );
var data = {
customer_id: $a.data( "customer" ),
product_id: $a.data( "product" )
};
$.post( "/ajax/wish-list", data, function ( res ) {
if( res.success ) {
iziToast.success({
title: "Success",
message: res.success
});
} else {
iziToast.error({
title: "Error",
message: res.error
});
}
});
return false;
});
iziToast è un plugin per le notifiche privo di dipendenze da librerie di terze parti, quindi è utilizzabile anche con un approccio non basato su jQuery. In questo caso viene mostrata a schermo una notifica diversa a seconda che il prodotto sia stato aggiunto alla wish list del cliente o meno.
Rimuovere record dalla whis list
La procedura di rimozione avviene invece all'interno del profilo del cliente ed ha bisogno degli stessi dati, ossia dell'ID del prodotto e dell'ID dell'utente corrente.
Definiremo quindi il seguente metodo AJAX nel nostro controller:
public function removeFromWishList(Request $request)
{
$customer_id = $request->get('customer_id');
$product_id = $request->get('product_id');
$entry = WishList::where([
['customer_id', '=', $customer_id],
['product_id', '=', $product_id],
])->first();
$entry->delete();
return response()->json(['success' => true]);
}
Ricevendo dal client i dati sopracitati, possiamo selezionare il record corrispondente dal database e quindi eliminarlo invocando il metodo delete()
del modello.
Lato client il codice JavaScript sarà strutturato come segue:
$( ".remove-from-wish-list" ).click(function() {
var $a = $( this );
var data = {
customer_id: $a.data( "customer" ),
product_id: $a.data( "product" )
};
$.post( "/ajax/wish-list-remove", data, function ( res ) {
if( res.success ) {
$a.parents( "tr" ).remove();
}
});
return false;
});
Se la richiesta ha avuto successo e il record è stato rimosso dalla wish list del cliente rimuoviamo dinamicamente la riga della tabella che corrisponde al record.
In questo caso avremmo anche potuto aggiungere una routine AJAX che vada a gestire eventuali errori nel metodo del nostro controller. Tipicamente se si verifica ad esempio un errore nella query al database, Laravel restituisce un errore HTTP 500. Questo errore può essere intercettato da un handler specifico di jQuery, volendo anche da un handler globale come ajaxError. Quest'ultima soluzione ha l'indubbio vantaggio di raccogliere in un solo punto tutta la gestione degli errori HTTP ricevuti durante le richieste AJAX.