queryBuilder = $queryBuilder; $this->image = $image; $this->settings = $settings; $this->logger = $logger; } protected function configure(): void { $this->addArgument( 'product_id', InputArgument::OPTIONAL, 'ID товара для прогрева кеша (если не указан, прогреваются все товары)' ); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $productId = $input->getArgument('product_id'); $io->title('Прогрев кеша изображений товаров'); // Получаем настройки $aspectRatio = $this->settings->get('app.image_aspect_ratio', '1:1'); $cropAlgorithm = $this->settings->get('app.image_crop_algorithm', 'cover'); [$imageWidth, $imageHeight] = ImageUtils::aspectRatioToSize($aspectRatio); $languageId = $this->settings->config()->getApp()->getLanguageId(); $io->section('Настройки'); $io->listing([ "Соотношение сторон: {$aspectRatio}", "Алгоритм обрезки: {$cropAlgorithm}", "Размер изображения: {$imageWidth}x{$imageHeight}", "Размер миниатюры: 500x500", "Размер большого изображения: 1000x1000", ]); // Получаем список товаров $products = $this->getProducts($productId, $languageId); if (empty($products)) { $io->warning('Товары не найдены'); return Command::SUCCESS; } $totalProducts = count($products); $io->section("Найдено товаров: {$totalProducts}"); $stats = [ 'products' => 0, 'main_images' => 0, 'additional_images' => 0, 'thumbnails' => 0, 'large_images' => 0, 'errors' => 0, ]; $progressBar = $io->createProgressBar($totalProducts); $progressBar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %message%'); $progressBar->setMessage('Обработка товаров...'); $progressBar->start(); foreach ($products as $product) { $productId = $product['product_id']; $productName = $product['product_name'] ?? "ID: {$productId}"; $progressBar->setMessage("Товар: {$productName}"); try { // Прогреваем основное изображение товара if (!empty($product['product_image'])) { try { $this->image->make($product['product_image']) ->crop($cropAlgorithm, $imageWidth, $imageHeight) ->url(); $stats['main_images']++; } catch (Exception $e) { $this->logger->error("Ошибка при прогреве основного изображения товара {$productId}: " . $e->getMessage()); $stats['errors']++; } } // Получаем дополнительные изображения товара $additionalImages = $this->getProductAdditionalImages($productId); $processedAdditional = 0; foreach ($additionalImages as $imagePath) { if ($processedAdditional >= 2) { break; // Ограничиваем до 2 дополнительных изображений, как в ProductsService } try { $this->image->make($imagePath) ->crop($cropAlgorithm, $imageWidth, $imageHeight) ->url(); $stats['additional_images']++; $processedAdditional++; } catch (Exception $e) { $this->logger->error("Ошибка при прогреве дополнительного изображения товара {$productId}: " . $e->getMessage()); $stats['errors']++; } } // Прогреваем изображения для детальной страницы (миниатюры и большие) $allImages = []; if (!empty($product['product_image'])) { $allImages[] = $product['product_image']; } $allImages = array_merge($allImages, $additionalImages); foreach ($allImages as $imagePath) { try { // Миниатюра $this->image->make($imagePath) ->contain(500, 500) ->url(); $stats['thumbnails']++; // Большое изображение $this->image->make($imagePath) ->resize(1000, 1000) ->url(); $stats['large_images']++; } catch (Exception $e) { $this->logger->error("Ошибка при прогреве изображений для детальной страницы товара {$productId}: " . $e->getMessage()); $stats['errors']++; } } $stats['products']++; } catch (Exception $e) { $this->logger->error("Ошибка при обработке товара {$productId}: " . $e->getMessage()); $stats['errors']++; } $progressBar->advance(); } $progressBar->setMessage('Завершено'); $progressBar->finish(); $io->newLine(2); // Выводим статистику $io->section('Статистика'); $io->table( ['Метрика', 'Значение'], [ ['Обработано товаров', $stats['products']], ['Основных изображений', $stats['main_images']], ['Дополнительных изображений', $stats['additional_images']], ['Миниатюр (500x500)', $stats['thumbnails']], ['Больших изображений (1000x1000)', $stats['large_images']], ['Ошибок', $stats['errors']], ] ); if ($stats['errors'] > 0) { $io->warning("Обнаружено {$stats['errors']} ошибок. Проверьте логи для подробностей."); } else { $io->success('Кеш изображений успешно прогрет!'); } return Command::SUCCESS; } /** * Получает список товаров для прогрева кеша */ private function getProducts(?string $productId, int $languageId): array { $query = $this->queryBuilder->newQuery() ->select([ 'products.product_id' => 'product_id', 'products.image' => 'product_image', 'product_description.name' => 'product_name', ]) ->from(db_table('product'), 'products') ->join( db_table('product_description') . ' AS product_description', function (JoinClause $join) use ($languageId) { $join->on('products.product_id', '=', 'product_description.product_id') ->where('product_description.language_id', '=', $languageId); } ) ->where('products.status', '=', 1) ->whereRaw('products.date_available < NOW()'); if ($productId !== null) { $query->where('products.product_id', '=', (int) $productId); } return $query->orderBy('products.product_id', 'ASC')->get(); } /** * Получает дополнительные изображения товара */ private function getProductAdditionalImages(int $productId): array { $images = $this->queryBuilder->newQuery() ->select(['products_images.image' => 'image']) ->from(db_table('product_image'), 'products_images') ->where('products_images.product_id', '=', $productId) ->orderBy('products_images.sort_order') ->get(); return Arr::pluck($images, 'image'); } }