tomeet/laravel-footprint
Composer 安装命令:
composer require tomeet/laravel-footprint
包简介
User footprint (browsing history) feature for Laravel Application.
README 文档
README
👣 User footprint (browsing history) feature for Laravel Application.
Features
- 🎯 Passive Tracking - Automatically record user browsing history via middleware
- 🔄 Update on Revisit - Same object revisits update the existing record, keeping the list fresh
- 📸 Data Snapshot - Save title, image, and metadata at browse time (survives object deletion)
- 🔒 Multi-Guard Support - Works with web session, Sanctum, JWT, and custom guards
- ⚡ Async Recording - Supports after-response dispatch or queue jobs
- 🧩 Polymorphic - Track any Eloquent model (Product, Post, Article, etc.)
Installation
composer require tomeet/laravel-footprint
Publish Configuration & Migrations
php artisan vendor:publish --provider="Tomeet\Laravel\Footprint\FootprintServiceProvider"
Run Migrations
php artisan migrate
Configuration
// config/footprint.php return [ 'uuids' => false, 'user_model' => App\Models\User::class, 'user_foreign_key' => 'user_id', 'footprint_table' => 'footprints', 'footprint_model' => \Tomeet\Laravel\Footprint\Footprint::class, // Supported authentication guards 'guards' => ['web', 'api', 'sanctum'], 'middleware' => [ 'enabled' => true, 'auto_attach_web' => false, 'auto_attach_api' => false, 'web_route_patterns' => ['products.show', 'posts.show'], 'api_route_patterns' => ['api.products.show', 'api.posts.show'], 'except_routes' => ['admin.*', 'api.auth.*'], 'auth_only' => true, 'async' => 'afterResponse', // afterResponse | queue | sync ], 'queue' => [ 'enabled' => true, 'connection' => env('QUEUE_CONNECTION', 'sync'), 'queue' => 'default', ], 'route_parameters' => [ 'products.show' => 'product', 'posts.show' => 'post', 'api.products.show' => 'product', 'api.posts.show' => 'post', ], 'prune' => [ 'enabled' => true, 'days' => 30, ], ];
Setup
1. Add Footprinter trait to your User model
use Tomeet\Laravel\Footprint\Traits\Footprinter; class User extends Authenticatable { use Footprinter; }
2. Add Footprintable trait to models you want to track
use Tomeet\Laravel\Footprint\Traits\Footprintable; class Product extends Model { use Footprintable; // Optional: customize snapshot metadata public function getFootprintMeta(): array { return [ 'price' => $this->price, 'original_price' => $this->original_price, 'category_id' => $this->category_id, ]; } }
Usage
Automatic Tracking via Middleware (Recommended)
Route-level middleware
// routes/web.php Route::middleware(['auth', 'footprint'])->group(function () { Route::get('/products/{product}', [ProductController::class, 'show'])->name('products.show'); }); // routes/api.php Route::middleware(['auth:sanctum', 'footprint'])->group(function () { Route::get('/products/{product}', [ProductController::class, 'show'])->name('api.products.show'); });
Auto-attach via configuration
// config/footprint.php 'middleware' => [ 'auto_attach_web' => true, 'auto_attach_api' => true, 'route_patterns' => ['*.show'], ],
Manual Tracking (when middleware is disabled)
// config/footprint.php 'middleware' => ['enabled' => false] // In your controller public function show(Product $product) { auth()->user()?->recordFootprint($product); return response()->json($product); }
API
User (Footprinter)
$user = User::find(1); // Record a footprint manually $user->recordFootprint($product); // Get paginated footprints $user->footprintPaginate(20); // Get recent footprints $user->recentFootprints(10); // Get footprint items as a query builder $user->getFootprintItems(Product::class)->where('status', 'active')->get(); // Check if user has viewed an object $user->hasFootprinted($product); // Get specific footprint record $user->getFootprintOf($product); // Clear all footprints $user->clearFootprints(); // Clear footprints by type $user->clearFootprintsByType(Product::class); // Attach has_footprinted status to a collection (avoids N+1) $products = Product::paginate(20); $user->attachFootprintStatus($products);
Model (Footprintable)
$product = Product::find(1); // Get all footprints for this product $product->footprints; // Get users who viewed this product $product->footprinters; // Count unique viewers $product->uniqueFootprintersCount(); // Total footprint records $product->totalFootprintsCount(); // Check if a specific user viewed $product->hasBeenFootprintedBy($user); // Get recent viewers $product->recentFootprinters(10);
JSON API Example
class FootprintController extends Controller { public function index(Request $request) { $footprints = $request->user()->footprintPaginate(20); return response()->json([ 'data' => $footprints->map(fn ($fp) => [ 'id' => $fp->id, 'title' => $fp->title, 'image' => $fp->image, 'meta' => $fp->meta, 'viewed_at' => $fp->viewed_at->toIso8601String(), 'viewed_at_human' => $fp->viewed_at->diffForHumans(), 'is_available' => $fp->footprintable !== null, 'footprintable' => $fp->footprintable?->only(['id', 'price']), ]), 'meta' => [ 'current_page' => $footprints->currentPage(), 'last_page' => $footprints->lastPage(), 'per_page' => $footprints->perPage(), 'total' => $footprints->total(), ], ]); } }
Pruning Old Records
// app/Console/Kernel.php protected function schedule(Schedule $schedule): void { $schedule->command('model:prune', [ '--model' => [\Tomeet\Laravel\Footprint\Footprint::class], ])->daily(); }
Or manually:
php artisan model:prune --model="Tomeet\Laravel\Footprint\Footprint"
Why Middleware Instead of Manual Calls?
| Favorite (Active) | Footprint (Passive) | |
|---|---|---|
| Trigger | User clicks "Favorite" button | User visits a page |
| Intent | Explicit action | Implicit behavior |
| Best Practice | Manual call in controller | Middleware auto-capture |
| Risk of Missing | Low (developer chooses) | High (easy to forget) |
Footprint is designed to not require any code changes in your controllers.
Related Packages
- overtrue/laravel-favorite - User favorite feature
- overtrue/laravel-follow - User follow feature
- overtrue/laravel-like - User like feature
License
MIT
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-06-15