baks-dev/products-favorite
Laravel/PHP module for managing product favorites (wishlist): add/remove products to a user’s favorites, store and retrieve favorite lists, and integrate into e-commerce product pages. Requires PHP 8.4+.
Installation
composer require baks-dev/products-favorite
Publish the package config and migrations:
php artisan vendor:publish --provider="BaksDev\ProductsFavorite\ProductsFavoriteServiceProvider" --tag="config"
php artisan vendor:publish --provider="BaksDev\ProductsFavorite\ProductsFavoriteServiceProvider" --tag="migrations"
php artisan migrate
First Use Case: Adding Favorite Logic to a Product
Inject the BaksDev\ProductsFavorite\Contracts\FavoriteService into your controller:
use BaksDev\ProductsFavorite\Contracts\FavoriteService;
class ProductController extends Controller
{
public function __construct(
private FavoriteService $favoriteService
) {}
public function toggleFavorite(Request $request, Product $product)
{
$this->favoriteService->toggle($request->user(), $product);
return response()->json(['status' => 'success']);
}
}
Key Files to Review
config/products-favorite.php (for customization)app/Models/Product.php (if extending the HasFavorites trait)routes/web.php (for default API routes)User Favorite Management
// Toggle favorite status
$favoriteService->toggle($user, $product);
// Check if product is favorited
$isFavorited = $favoriteService->isFavorited($user, $product);
// Get user's favorite products
$favorites = $favoriteService->getFavorites($user);
Model Integration
Extend your Product model with the HasFavorites trait:
use BaksDev\ProductsFavorite\Traits\HasFavorites;
class Product extends Model
{
use HasFavorites;
}
Now use model methods directly:
$product->toggleFavorite($user);
$product->isFavoritedBy($user);
API Endpoints The package includes default routes for:
POST /api/favorites (toggle favorite)GET /api/favorites (list user favorites)
Customize via routes/web.php or override middleware.Event Handling Listen for favorite events:
// In EventServiceProvider
protected $listen = [
'BaksDev\ProductsFavorite\Events\FavoriteAdded' => [
'App\Listeners\LogFavoriteActivity',
],
'BaksDev\ProductsFavorite\Events\FavoriteRemoved' => [
'App\Listeners\NotifyUser',
],
];
Batch Operations
// Add multiple products to favorites
$favoriteService->addMultiple($user, [$product1, $product2]);
// Remove multiple products
$favoriteService->removeMultiple($user, [$product1, $product2]);
Authentication
public function handle(Request $request, Closure $next)
{
if (!$request->user()) {
abort(401);
}
return $next($request);
}
Model Relationships
Product model has a user_id column if using the default pivot table. Customize via config:
'pivot' => [
'table' => 'product_user_favorites',
'foreign_key' => 'product_id',
'related_key' => 'user_id',
],
Caching
isFavorited) may benefit from caching. Add a cache layer:
$isFavorited = Cache::remember(
"favorite:{$user->id}:{$product->id}",
now()->addHours(1),
fn() => $favoriteService->isFavorited($user, $product)
);
Performance
with() selectively:
// Bad: Loads favorites for ALL products
$products = Product::with('favorites')->get();
// Good: Load only needed favorites
$products = Product::whereIn('id', $ids)->with(['favorites' => function($query) use ($user) {
$query->where('user_id', $user->id);
}])->get();
Testing
FavoriteService facade in tests:
$this->actingAs($user);
$this->postJson('/api/favorites', ['product_id' => $product->id]);
$this->assertDatabaseHas('product_user_favorites', [
'product_id' => $product->id,
'user_id' => $user->id,
]);
Customizing the Pivot Table
Extend the FavoriteService to use a custom pivot table:
class CustomFavoriteService extends FavoriteService
{
protected $pivotTable = 'custom_favorites';
}
Bind it in AppServiceProvider:
$this->app->bind(
\BaksDev\ProductsFavorite\Contracts\FavoriteService::class,
CustomFavoriteService::class
);
Soft Deletes
If using soft deletes, ensure the pivot table has deleted_at and update the service:
// In CustomFavoriteService
public function toggle(User $user, Product $product)
{
$exists = $this->favoriteModel->where([
'product_id' => $product->id,
'user_id' => $user->id,
])->exists();
if ($exists) {
$this->favoriteModel->where([
'product_id' => $product->id,
'user_id' => $user->id,
])->delete(); // Soft delete
} else {
$this->favoriteModel->create([
'product_id' => $product->id,
'user_id' => $user->id,
]);
}
}
API Rate Limiting Protect favorite endpoints with Laravel's throttle middleware:
Route::middleware(['throttle:10,1'])->group(function () {
Route::post('/api/favorites', [FavoriteController::class, 'toggle']);
});
Localization
Customize language strings in resources/lang/{locale}/products-favorite.php:
return [
'added' => 'Product added to favorites!',
'removed' => 'Product removed from favorites.',
];
Debugging
DB::enableQueryLog();
$favoriteService->toggle($user, $product);
dd(DB::getQueryLog());
Schema::table('product_user_favorites', function (Blueprint $table) {
$table->foreign('product_id')->references('id')->on('products');
$table->foreign('user_id')->references('id')->on('users');
});
How can I help you explore Laravel packages today?