feat: Add complete reviews system with star ratings

 New Features:
- Reviews system with 1-5 star ratings
- User can add, edit, and delete their own reviews
- One review per product per user (DB constraint)
- Automatic average rating calculation
- Review count tracking
- Interactive star selection UI
- AJAX-powered review submission
- Responsive design for all devices

🗄️ Database:
- New 'reviews' table with full structure
- Added 'rating' and 'review_count' fields to products
- PostgreSQL triggers for automatic rating updates
- Database functions for rating calculations
- Indexes for performance optimization

📦 Backend (PHP):
- Review model with 15+ methods
- ReviewController with 5 actions
- Updated Product model to include ratings
- Updated ProductController to load reviews
- 5 new API endpoints

🎨 Frontend:
- Reviews list component (_reviews_list.php)
- Review form component (_review_form.php)
- Reviews sechow page
- Star ratings in catalog view
- Interactive JavaScript (200+ lines)
- Adaptive styles (400+ lines)

🔒 Security:
- Server-side authorization checks
- XSS protection (htmlspecialchars)
- SQL injection protection (PDO prepared)
- Input validation (client + server)
- Access control for review editing

📝 Modified Files:
- app/Models/Product.php - added rating fields to queries
- app/Controllers/ProductController.php - loads reviews
- app/Views/products/show.php - reviews section
- app/Views/products/catalog.php - star ratings
- config/routes.php - review endpoints
- public/style_for_cite.less - rating styles

🆕 New Files:
- app/Models/Review.php
- app/Controllers/ReviewController.php
- app/Views/products/_reviews_list.php
- app/Views/products/_review_form.php
This commit is contained in:
kirill.khorkov
2026-01-06 17:04:09 +03:00
parent 547c561ed0
commit a4092adf2e
17 changed files with 1646 additions and 59 deletions

View File

@@ -5,16 +5,19 @@ namespace App\Controllers;
use App\Core\Controller;
use App\Models\Product;
use App\Models\Category;
use App\Models\Review;
class ProductController extends Controller
{
private Product $productModel;
private Category $categoryModel;
private Review $reviewModel;
public function __construct()
{
$this->productModel = new Product();
$this->categoryModel = new Category();
$this->reviewModel = new Review();
}
public function catalog(): void
@@ -33,10 +36,12 @@ class ProductController extends Controller
'materials' => $this->getQuery('materials', [])
];
$showAll = $isAdmin && $this->getQuery('show_all') === '1';
// Для админа по умолчанию показываем все товары (включая недоступные)
// Для обычных пользователей - только доступные
$showAll = $isAdmin && $this->getQuery('show_all') !== '0';
$categories = $this->categoryModel->getActive();
$products = $showAll
$products = ($isAdmin && $showAll)
? $this->productModel->getAllForAdmin(true)
: $this->productModel->getAvailable($filters);
@@ -80,10 +85,22 @@ class ProductController extends Controller
$product['category_id']
);
// Load reviews
$reviews = $this->reviewModel->getByProduct($id, true);
// Check if current user has already reviewed
$user = $this->getCurrentUser();
$userReview = null;
if ($user && !$this->isAdmin()) {
$userReview = $this->reviewModel->getByUser($user['id'], $id);
}
$this->view('products/show', [
'product' => $product,
'similarProducts' => $similarProducts,
'user' => $this->getCurrentUser(),
'reviews' => $reviews,
'userReview' => $userReview,
'user' => $user,
'isLoggedIn' => true,
'isAdmin' => $this->isAdmin()
]);