213 lines
8.5 KiB
PHP
213 lines
8.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Controllers\CatalogController;
|
|
use App\Controllers\CartController;
|
|
use App\Controllers\HomeController;
|
|
use App\Controllers\PageController;
|
|
use App\Controllers\PriceRequestController;
|
|
use App\Controllers\WishlistRequestController;
|
|
use App\Core\Router;
|
|
use App\Repositories\CategoryRepository;
|
|
use App\Repositories\ProductRepository;
|
|
|
|
require_once dirname(__DIR__) . '/app/bootstrap.php';
|
|
|
|
$router = new Router();
|
|
|
|
$absoluteSiteUrl = static function (): string {
|
|
$siteUrl = rtrim((string) app_env('SITE_URL', ''), '/');
|
|
if ($siteUrl !== '') {
|
|
return $siteUrl;
|
|
}
|
|
|
|
$host = preg_replace('/[^a-z0-9.\-:]/i', '', (string) ($_SERVER['HTTP_HOST'] ?? 'new.rybstock.ru'));
|
|
|
|
return 'https://' . $host;
|
|
};
|
|
|
|
$xmlEscape = static fn (string $value): string => htmlspecialchars($value, ENT_XML1 | ENT_COMPAT, 'UTF-8');
|
|
|
|
$sitemapHandler = static function () use ($absoluteSiteUrl, $xmlEscape): void {
|
|
$baseUrl = $absoluteSiteUrl();
|
|
$today = date('Y-m-d');
|
|
$urls = [];
|
|
|
|
$addUrl = static function (
|
|
string $path,
|
|
string $priority,
|
|
string $changefreq = 'weekly',
|
|
?string $lastmod = null
|
|
) use (&$urls, $baseUrl, $today): void {
|
|
$urls[] = [
|
|
'loc' => $baseUrl . ($path === '/' ? '/' : '/' . ltrim($path, '/')),
|
|
'lastmod' => $lastmod ?: $today,
|
|
'changefreq' => $changefreq,
|
|
'priority' => $priority,
|
|
];
|
|
};
|
|
|
|
$addUrl('/', '1.0', 'daily');
|
|
$addUrl('/catalog', '0.9', 'daily');
|
|
$addUrl('/promo', '0.8', 'daily');
|
|
$addUrl('/new', '0.8', 'daily');
|
|
$addUrl('/delivery', '0.6', 'monthly');
|
|
$addUrl('/payment', '0.5', 'monthly');
|
|
$addUrl('/contacts', '0.5', 'monthly');
|
|
$addUrl('/returns', '0.4', 'monthly');
|
|
|
|
try {
|
|
foreach ((new CategoryRepository())->active() as $category) {
|
|
$addUrl('/catalog/' . (string) $category['slug'], '0.7', 'weekly');
|
|
}
|
|
|
|
foreach ((new ProductRepository())->sitemapProducts() as $product) {
|
|
$dateSource = $product['updated_at'] ?: ($product['published_at'] ?: $product['created_at']);
|
|
$lastmod = $dateSource ? date('Y-m-d', strtotime((string) $dateSource)) : $today;
|
|
$addUrl('/product/' . (string) $product['slug'], '0.6', 'weekly', $lastmod);
|
|
}
|
|
} catch (Throwable) {
|
|
// Keep a valid sitemap available even during database maintenance.
|
|
}
|
|
|
|
header('Content-Type: application/xml; charset=UTF-8');
|
|
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
echo "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n";
|
|
foreach ($urls as $url) {
|
|
echo " <url>\n";
|
|
echo ' <loc>' . $xmlEscape($url['loc']) . "</loc>\n";
|
|
echo ' <lastmod>' . $xmlEscape($url['lastmod']) . "</lastmod>\n";
|
|
echo ' <changefreq>' . $xmlEscape($url['changefreq']) . "</changefreq>\n";
|
|
echo ' <priority>' . $xmlEscape($url['priority']) . "</priority>\n";
|
|
echo " </url>\n";
|
|
}
|
|
echo "</urlset>\n";
|
|
};
|
|
|
|
$robotsHandler = static function () use ($absoluteSiteUrl): void {
|
|
header('Content-Type: text/plain; charset=UTF-8');
|
|
echo "User-agent: *\n";
|
|
echo "Allow: /\n";
|
|
echo "Disallow: /admin/\n";
|
|
echo "Disallow: /public/admin/\n";
|
|
echo "Disallow: /cart\n";
|
|
echo "\n";
|
|
echo 'Sitemap: ' . $absoluteSiteUrl() . "/sitemap.xml\n";
|
|
};
|
|
|
|
$catalogSearchHandler = static function (?string $rawQuery = null): void {
|
|
$queryParameters = [];
|
|
parse_str((string) (parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_QUERY) ?? ''), $queryParameters);
|
|
|
|
$query = trim((string) ($rawQuery ?? $_GET['q'] ?? $queryParameters['q'] ?? ''));
|
|
if ($query === '') {
|
|
(new CatalogController())->index();
|
|
return;
|
|
}
|
|
|
|
$_GET['q'] = $query;
|
|
|
|
$perPage = 48;
|
|
$limit = isset($_GET['limit']) ? max($perPage, min((int) $_GET['limit'], 5000)) : $perPage;
|
|
$page = max(1, (int) ($_GET['page'] ?? 1));
|
|
$offset = isset($_GET['limit']) ? 0 : (($page - 1) * $perPage);
|
|
|
|
$categoryRepository = new CategoryRepository();
|
|
$productRepository = new ProductRepository();
|
|
|
|
if (method_exists($productRepository, 'searchCatalog')) {
|
|
$searchResult = $productRepository->searchCatalog($query, $limit, $offset, true);
|
|
$products = $searchResult['products'];
|
|
$total = $searchResult['total'];
|
|
} else {
|
|
$allProducts = $productRepository->catalogPreview(5000, 0, true);
|
|
$needle = function_exists('mb_strtolower') ? mb_strtolower($query, 'UTF-8') : strtolower($query);
|
|
$words = array_values(array_filter(preg_split('/\s+/u', $needle) ?: []));
|
|
|
|
$ranked = [];
|
|
foreach ($allProducts as $product) {
|
|
$haystack = implode(' ', [
|
|
(string) ($product['name'] ?? ''),
|
|
(string) ($product['short_description'] ?? ''),
|
|
(string) ($product['category_name'] ?? ''),
|
|
(string) ($product['display_category_name'] ?? ''),
|
|
(string) ($product['categories_path'] ?? ''),
|
|
]);
|
|
$haystack = function_exists('mb_strtolower') ? mb_strtolower($haystack, 'UTF-8') : strtolower($haystack);
|
|
|
|
$score = 0;
|
|
if ($needle !== '' && str_contains($haystack, $needle)) {
|
|
$score += 100;
|
|
}
|
|
|
|
foreach ($words as $word) {
|
|
if ($word !== '' && str_contains($haystack, $word)) {
|
|
$score += 20;
|
|
}
|
|
}
|
|
|
|
if ($score > 0) {
|
|
$product['_search_score'] = $score;
|
|
$ranked[] = $product;
|
|
}
|
|
}
|
|
|
|
usort($ranked, static fn (array $a, array $b): int => ($b['_search_score'] ?? 0) <=> ($a['_search_score'] ?? 0));
|
|
|
|
$total = count($ranked);
|
|
$products = array_slice($ranked, $offset, $limit);
|
|
}
|
|
|
|
$shown = min($total, $offset + count($products));
|
|
$basePath = '/search/' . rawurlencode($query);
|
|
|
|
view('catalog/index', [
|
|
'title' => 'Поиск по каталогу Рыбсток - ' . $query,
|
|
'metaDescription' => 'Результаты поиска по каталогу Рыбсток: ' . $query,
|
|
'metaKeywords' => $query . ', Рыбсток, каталог продуктов',
|
|
'breadcrumbs' => [
|
|
['title' => 'Главная', 'url' => '/'],
|
|
['title' => 'Каталог', 'url' => '/catalog'],
|
|
['title' => 'Поиск'],
|
|
],
|
|
'categories' => $categoryRepository->tree(),
|
|
'currentCategory' => null,
|
|
'products' => $products,
|
|
'searchQuery' => $query,
|
|
'pagination' => [
|
|
'base_path' => $basePath,
|
|
'total' => $total,
|
|
'shown' => $shown,
|
|
'page' => $page,
|
|
'pages' => max(1, (int) ceil($total / $perPage)),
|
|
'per_page' => $perPage,
|
|
'limit' => $limit,
|
|
'has_more' => $shown < $total,
|
|
'next_limit' => min($total, max($shown, $limit) + $perPage),
|
|
'cumulative' => isset($_GET['limit']),
|
|
],
|
|
]);
|
|
};
|
|
|
|
$router->get('/', static fn () => (new HomeController())->index());
|
|
$router->get('/robots.txt', $robotsHandler);
|
|
$router->get('/sitemap.xml', $sitemapHandler);
|
|
$router->post('/price-request', static fn () => (new PriceRequestController())->store());
|
|
$router->post('/wishlist-request', static fn () => (new WishlistRequestController())->store());
|
|
$router->post('/api/cart/sync', static fn () => (new CartController())->sync());
|
|
$router->get('/search', static fn () => $catalogSearchHandler());
|
|
$router->get('/search/{query}', static fn (string $query) => $catalogSearchHandler($query));
|
|
$router->get('/promo', static fn () => (new CatalogController())->promo());
|
|
$router->get('/new', static fn () => (new CatalogController())->newest());
|
|
$router->get('/catalog', static fn () => trim((string) ($_GET['q'] ?? '')) !== '' ? $catalogSearchHandler() : (new CatalogController())->index());
|
|
$router->get('/delivery', static fn () => (new PageController())->delivery());
|
|
$router->get('/payment', static fn () => (new PageController())->payment());
|
|
$router->get('/contacts', static fn () => (new PageController())->contacts());
|
|
$router->get('/returns', static fn () => (new PageController())->returns());
|
|
$router->get('/cart', static fn () => (new PageController())->cart());
|
|
$router->get('/product/{slug}', static fn (string $slug) => (new CatalogController())->product($slug));
|
|
$router->get('/catalog/{slug}', static fn (string $slug) => (new CatalogController())->category($slug));
|
|
|
|
$router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|