baks-dev/products-viewed
Laravel/PHP модуль для отслеживания и вывода просмотренных товаров. Установка через Composer, рендер в Twig: render_products_viewed(invariable_id|null). Поддерживает установку ассетов, миграции Doctrine и тесты PHPUnit.
Installation
composer require baks-dev/products-viewed
php artisan vendor:publish --provider="BaksDev\ProductsViewed\ProductsViewedServiceProvider" --tag="config"
php bin/console baks:assets:install
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
Enable Middleware
Add the middleware to your app/Http/Kernel.php under the $middleware or $middlewareGroups['web'] array:
\BaksDev\ProductsViewed\Http\Middleware\TrackProductViewed::class,
First Use Case
Track product views by passing the invariable_id (or product_id) to your Twig template:
{% set productId = product.invariable_id %}
{{ render_products_viewed(productId) }}
Ensure your route/controller passes the product entity to the view.
config/products-viewed.php for:
tracking_limit: Max views per session/user.storage: Database/table settings (default: products_viewed).middleware: Custom middleware for view tracking logic.TrackProductViewed in app/Http/Middleware/ to understand how views are captured (e.g., via session or request data).BaksDev\ProductsViewed\Twig\ProductsViewedExtension for template methods and customization points.BaksDev\ProductsViewed\Entity\ProductViewed for database schema and relationships.TrackProductViewed middleware to auto-capture views when products are accessed.Kernel.php.invariable_id (or product_id) in the request.// In your controller
public function show(Product $product) {
return view('product.show', ['product' => $product]);
}
The middleware automatically logs the view when the route is hit.render_products_viewed Twig function.invariable_id to the template.{# Show recently viewed products #}
{{ render_products_viewed(user.id, 5) }}
ProductViewed events to trigger side effects (e.g., analytics, recommendations).php artisan vendor:publish --provider="BaksDev\ProductsViewed\ProductsViewedServiceProvider" --tag="events"
// app/Listeners/ProductViewedListener.php
public function handle(ProductViewed $event) {
// Send to analytics, update recommendations, etc.
}
EventServiceProvider:
protected $listen = [
\BaksDev\ProductsViewed\Events\ProductViewed::class => [
\App\Listeners\ProductViewedListener::class,
],
];
// app/Http/Controllers/ProductViewedController.php
public function index(Request $request) {
$views = ProductViewedRepository::getRecentViews($request->user(), 10);
return response()->json($views);
}
Route::get('/api/products/viewed', [ProductViewedController::class, 'index']);
ProductViewedRepository to use Redis:
public function getRecentViews(User $user, int $limit) {
$cacheKey = "recent_views_{$user->id}";
return Cache::remember($cacheKey, now()->addHours(1), function() use ($user, $limit) {
return $this->entityManager->getRepository(ProductViewed::class)
->findBy(['user' => $user->id], ['created_at' => 'DESC'], $limit);
});
}
BaksDev\ProductsViewed\Contracts\ViewStorageInterface.$this->app->bind(
ViewStorageInterface::class,
CustomViewStorage::class
);
$repository = $this->container->get(ProductViewedRepository::class);
$repository->bulkTrack([
['user_id' => 1, 'product_id' => 101, 'created_at' => now()],
['user_id' => 2, 'product_id' => 102, 'created_at' => now()],
]);
// app/Console/Commands/CleanupProductViews.php
public function handle() {
$this->entityManager->getRepository(ProductViewed::class)
->createQueryBuilder('pv')
->delete()
->where('pv.created_at < :date')
->setParameter('date', now()->subMonths(6))
->getQuery()
->execute();
}
app/Console/Kernel.php:
$schedule->command(CleanupProductViews::class)->monthly();
ProductViewed entity to include a tenant_id field.$repository->findBy(['user' => $user->id, 'tenant_id' => tenant()->id()]);
Middleware Timing
TrackProductViewed is placed before any middleware that might alter the request (e.g., authentication, localization).Database Schema Conflicts
products_viewed table may conflict with existing tables.'storage' => [
'table' => 'custom_product_views',
],
Twig vs. Blade
// app/Providers/BladeServiceProvider.php
Blade::directive('renderProductsViewed', function ($expression) {
return "<?php echo app('BaksDev\\ProductsViewed\\Twig\\ProductsViewedExtension')->renderProductsViewed({$expression}); ?>";
});
Usage:
@renderProductsViewed($product->invariable_id)
Performance with High Traffic
// In TrackProductViewed middleware
TrackProductView::dispatch($productId, $userId)->onQueue('product-views');
Then create a job:
// app/Jobs/TrackProductView.php
public function handle()
How can I help you explore Laravel packages today?