{"id":21361,"date":"2024-12-06T21:38:26","date_gmt":"2024-12-07T03:38:26","guid":{"rendered":"http:\/\/www.designandexecute.com\/designs\/?p=21361"},"modified":"2024-12-06T21:40:05","modified_gmt":"2024-12-07T03:40:05","slug":"scoring-system-in-laravel-php","status":"publish","type":"post","link":"https:\/\/www.designandexecute.com\/designs\/scoring-system-in-laravel-php\/","title":{"rendered":"C4 &#8211; Scoring System in Laravel (PHP)"},"content":{"rendered":"\n<h4 class=\"wp-block-heading\"><strong>Workflow<\/strong><\/h4>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Voting:<\/strong> Users can upvote photos, and their votes are stored in Redis as part of a sorted set (<code>ZSET<\/code>).<\/li><li><strong>Views:<\/strong> Each time a photo is viewed, the view count is incremented in Redis.<\/li><li><strong>Leaderboard:<\/strong> A combined score (e.g., based on votes and views) is calculated and stored for real-time ranking.<\/li><\/ul>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Setup Requirements<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\"><li>\nEnsure Redis is configured and connected in your Laravel project:\n<ul><li>In <code>.env<\/code>:\n<code>CACHE_DRIVER=redis\nREDIS_HOST=127.0.0.1\nREDIS_PORT=6379\n<\/code>\n<\/li><li>Install Redis support for Laravel if not already installed:\n<code>composer require predis\/predis\n<\/code>\n<\/li><\/ul>\n<\/li><li>\nAdd the Redis facade if needed:\n<code>use Illuminate\\Support\\Facades\\Redis;\n<\/code>\n<\/li><\/ol>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Code Implementation<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Voting Logic<\/strong><\/h4>\n\n\n\n<p>This method increments the vote count for a photo and updates the leaderboard score.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function voteForPhoto($userId, $photoId)\n{\n    $voteKey = \"photo:votes:$userId\"; \/\/ Track user votes\n    $leaderboardKey = \"photo:leaderboard\"; \/\/ Redis ZSET for ranking\n\n    \/\/ Check if the user has already voted for this photo\n    if (Redis::hexists($voteKey, $photoId)) {\n        return response()->json(['success' => false, 'message' => 'You have already voted for this photo.']);\n    }\n\n    \/\/ Increment the photo's score in the leaderboard\n    Redis::zincrby($leaderboardKey, 1, $photoId);\n\n    \/\/ Mark the photo as voted by the user\n    Redis::hset($voteKey, $photoId, 1);\n\n    return response()->json(['success' => true, 'message' => 'Vote recorded successfully.']);\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>View Tracking Logic<\/strong><\/h4>\n\n\n\n<p>This method increments the view count for a photo.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function recordPhotoView($photoId)\n{\n    $viewsKey = \"photo:views\"; \/\/ Redis HASH for view counts\n\n    \/\/ Increment the view count for the photo\n    Redis::hincrby($viewsKey, $photoId, 1);\n\n    return response()->json(['success' => true, 'message' => 'View recorded successfully.']);\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Retrieving the Leaderboard<\/strong><\/h4>\n\n\n\n<p>This method fetches the top N photos from the leaderboard.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function getLeaderboard($limit = 10)\n{\n    $leaderboardKey = \"photo:leaderboard\";\n\n    \/\/ Get the top N photos from the leaderboard\n    $leaderboard = Redis::zrevrange($leaderboardKey, 0, $limit - 1, ['WITHSCORES' => true]);\n\n    \/\/ Format the result for easier readability\n    $formattedLeaderboard = [];\n    foreach ($leaderboard as $photoId => $score) {\n        $formattedLeaderboard[] = [\n            'photo_id' => $photoId,\n            'score' => $score,\n        ];\n    }\n\n    return response()->json($formattedLeaderboard);\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Combining Votes and Views for Scoring<\/strong><\/h4>\n\n\n\n<p>If you want to dynamically calculate the leaderboard score based on a combination of votes and views (e.g., <code>score = votes * 0.7 + views * 0.3<\/code>), you can create a method to recompute scores periodically.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>public function recalculateLeaderboardScores()\n{\n    $leaderboardKey = \"photo:leaderboard\";\n    $viewsKey = \"photo:views\";\n\n    \/\/ Get all photos from the leaderboard\n    $photos = Redis::zrange($leaderboardKey, 0, -1);\n\n    foreach ($photos as $photoId) {\n        \/\/ Get votes and views for each photo\n        $votes = Redis::zscore($leaderboardKey, $photoId) ?? 0;\n        $views = Redis::hget($viewsKey, $photoId) ?? 0;\n\n        \/\/ Recalculate the score\n        $newScore = ($votes * 0.7) + ($views * 0.3);\n\n        \/\/ Update the score in the leaderboard\n        Redis::zadd($leaderboardKey, ['NX'], $newScore, $photoId);\n    }\n\n    return response()->json(['success' => true, 'message' => 'Leaderboard scores recalculated.']);\n}\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>API Endpoints Example<\/strong><\/h3>\n\n\n\n<p>In your Laravel <code>routes\/api.php<\/code>, you can define endpoints like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>use App\\Http\\Controllers\\LeaderboardController;\n\nRoute::post('\/vote', [LeaderboardController::class, 'voteForPhoto']);\nRoute::post('\/view', [LeaderboardController::class, 'recordPhotoView']);\nRoute::get('\/leaderboard', [LeaderboardController::class, 'getLeaderboard']);\nRoute::post('\/leaderboard\/recalculate', [LeaderboardController::class, 'recalculateLeaderboardScores']);\n<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Example Usage<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\"><li>\n<strong>Voting for a Photo<\/strong>\n<ul><li>API Call:\n<code>POST \/vote\n<\/code>\n<ul><li>Request Body:\n<code>{\n  \"userId\": \"123\",\n  \"photoId\": \"456\"\n}\n<\/code>\n<\/li><\/ul>\n<\/li><\/ul>\n<\/li><li>\n<strong>Recording a View<\/strong>\n<ul><li>API Call:\n<code>POST \/view\n<\/code>\n<ul><li>Request Body:\n<code>{\n  \"photoId\": \"456\"\n}\n<\/code>\n<\/li><\/ul>\n<\/li><\/ul>\n<\/li><li>\n<strong>Getting the Leaderboard<\/strong>\n<ul><li>API Call:\n<code>GET \/leaderboard\n<\/code>\n<ul><li>Response:\n<code>[\n  {\n    \"photo_id\": \"456\",\n    \"score\": \"10\"\n  },\n  {\n    \"photo_id\": \"789\",\n    \"score\": \"8\"\n  }\n]\n<\/code>\n<\/li><\/ul>\n<\/li><\/ul>\n<\/li><li>\n<strong>Recalculating Leaderboard Scores<\/strong>\n<ul><li>API Call:\n<code>POST \/leaderboard\/recalculate\n<\/code>\n<\/li><\/ul>\n<\/li><\/ol>\n\n\n\n<hr class=\"wp-block-separator\"\/>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Benefits of Redis in Laravel<\/strong><\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>Real-Time Performance:<\/strong> Redis ensures low latency for updates and reads.<\/li><li><strong>Scalable:<\/strong> Easily handles a growing number of votes, views, and leaderboard entries.<\/li><li><strong>Integration:<\/strong> Laravel&#8217;s Redis support makes the implementation seamless.<\/li><\/ul>\n\n\n\n<p>This setup provides a robust foundation for a real-time photo leaderboard system.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Workflow Voting: Users can upvote photos, and their votes are stored in Redis as part of a sorted set (ZSET). Views: Each time a photo is viewed, the view count is incremented in Redis. Leaderboard: A combined score (e.g., based on votes and views) is calculated and stored for real-time ranking. Setup Requirements Ensure Redis [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":21365,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[63],"tags":[],"class_list":["post-21361","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-programming"],"jetpack_featured_media_url":"https:\/\/www.designandexecute.com\/designs\/wp-content\/uploads\/2024\/12\/Redis-programming.jpg","_links":{"self":[{"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/posts\/21361","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/comments?post=21361"}],"version-history":[{"count":2,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/posts\/21361\/revisions"}],"predecessor-version":[{"id":21367,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/posts\/21361\/revisions\/21367"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/media\/21365"}],"wp:attachment":[{"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/media?parent=21361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/categories?post=21361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.designandexecute.com\/designs\/wp-json\/wp\/v2\/tags?post=21361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}