✨ 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
109 lines
3.5 KiB
PHP
109 lines
3.5 KiB
PHP
<?php
|
|
|
|
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
|
|
{
|
|
$this->requireAuth();
|
|
|
|
$user = $this->getCurrentUser();
|
|
$isAdmin = $this->isAdmin();
|
|
|
|
$filters = [
|
|
'category_id' => (int) $this->getQuery('category', 0),
|
|
'search' => $this->getQuery('search', ''),
|
|
'min_price' => (int) $this->getQuery('min_price', 0),
|
|
'max_price' => (int) $this->getQuery('max_price', 1000000),
|
|
'colors' => $this->getQuery('colors', []),
|
|
'materials' => $this->getQuery('materials', [])
|
|
];
|
|
|
|
// Для админа по умолчанию показываем все товары (включая недоступные)
|
|
// Для обычных пользователей - только доступные
|
|
$showAll = $isAdmin && $this->getQuery('show_all') !== '0';
|
|
|
|
$categories = $this->categoryModel->getActive();
|
|
$products = ($isAdmin && $showAll)
|
|
? $this->productModel->getAllForAdmin(true)
|
|
: $this->productModel->getAvailable($filters);
|
|
|
|
$availableColors = $this->productModel->getAvailableColors();
|
|
$availableMaterials = $this->productModel->getAvailableMaterials();
|
|
|
|
$subcategories = [];
|
|
if ($filters['category_id'] > 0) {
|
|
$subcategories = $this->categoryModel->getChildren($filters['category_id']);
|
|
}
|
|
|
|
$this->view('products/catalog', [
|
|
'user' => $user,
|
|
'isLoggedIn' => true,
|
|
'isAdmin' => $isAdmin,
|
|
'categories' => $categories,
|
|
'subcategories' => $subcategories,
|
|
'products' => $products,
|
|
'filters' => $filters,
|
|
'showAll' => $showAll,
|
|
'availableColors' => $availableColors,
|
|
'availableMaterials' => $availableMaterials,
|
|
'success' => $this->getQuery('success'),
|
|
'error' => $this->getQuery('error')
|
|
]);
|
|
}
|
|
|
|
public function show(int $id): void
|
|
{
|
|
$this->requireAuth();
|
|
|
|
$product = $this->productModel->findWithCategory($id);
|
|
|
|
if (!$product || (!$product['is_available'] && !$this->isAdmin())) {
|
|
$this->redirect('/catalog?error=product_not_found');
|
|
return;
|
|
}
|
|
|
|
$similarProducts = $this->productModel->getSimilar(
|
|
$id,
|
|
$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,
|
|
'reviews' => $reviews,
|
|
'userReview' => $userReview,
|
|
'user' => $user,
|
|
'isLoggedIn' => true,
|
|
'isAdmin' => $this->isAdmin()
|
|
]);
|
|
}
|
|
}
|