Files
ltsecurityinc/app/code/Lts/SearchAutocomplete/Controller/Ajax/Suggest.php
T

196 lines
8.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Lts\SearchAutocomplete\Controller\Ajax;
use Magento\Catalog\Helper\ImageFactory;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\ResourceModel\Category\CollectionFactory as CategoryCollectionFactory;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory as ProductCollectionFactory;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\Controller\Result\Json;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Search\Model\ResourceModel\Query\CollectionFactory as QueryCollectionFactory;
use Magento\Store\Model\StoreManagerInterface;
class Suggest extends Action implements HttpGetActionInterface
{
private JsonFactory $jsonFactory;
private ProductCollectionFactory $productCollectionFactory;
private CategoryCollectionFactory $categoryCollectionFactory;
private QueryCollectionFactory $queryCollectionFactory;
private StoreManagerInterface $storeManager;
private Visibility $productVisibility;
private ImageFactory $imageFactory;
private PriceCurrencyInterface $priceCurrency;
private StockRegistryInterface $stockRegistry;
public function __construct(
Context $context,
JsonFactory $jsonFactory,
ProductCollectionFactory $productCollectionFactory,
CategoryCollectionFactory $categoryCollectionFactory,
QueryCollectionFactory $queryCollectionFactory,
StoreManagerInterface $storeManager,
Visibility $productVisibility,
ImageFactory $imageFactory,
PriceCurrencyInterface $priceCurrency,
StockRegistryInterface $stockRegistry
) {
parent::__construct($context);
$this->jsonFactory = $jsonFactory;
$this->productCollectionFactory = $productCollectionFactory;
$this->categoryCollectionFactory = $categoryCollectionFactory;
$this->queryCollectionFactory = $queryCollectionFactory;
$this->storeManager = $storeManager;
$this->productVisibility = $productVisibility;
$this->imageFactory = $imageFactory;
$this->priceCurrency = $priceCurrency;
$this->stockRegistry = $stockRegistry;
}
public function execute(): Json
{
$result = $this->jsonFactory->create();
$term = trim((string)$this->getRequest()->getParam('q'));
if (mb_strlen($term) < 2) {
return $result->setData(['suggestions' => [], 'products' => [], 'total' => 0]);
}
$store = $this->storeManager->getStore();
$like = '%' . addcslashes($term, '%_') . '%';
$products = $this->productCollectionFactory->create();
$products->setStore($store)
->addStoreFilter($store)
->setVisibility($this->productVisibility->getVisibleInSiteIds())
->addAttributeToSelect(['name', 'sku', 'small_image', 'thumbnail', 'price', 'special_price'])
->addAttributeToFilter([
['attribute' => 'name', 'like' => $like],
['attribute' => 'sku', 'like' => $like]
], null, 'left')
->addAttributeToSort('name', 'ASC')
->setPageSize(5)
->setCurPage(1);
$total = (int)$products->getSize();
$productData = [];
foreach ($products as $product) {
try {
$inStock = (bool)$this->stockRegistry->getStockItem((int)$product->getId())->getIsInStock();
} catch (\Throwable $exception) {
$inStock = true;
}
$imageHelper = $this->imageFactory->create()->init($product, 'product_small_image');
$connection = $products->getConnection();
$galleryTable = $products->getTable('catalog_product_entity_media_gallery');
$linkTable = $products->getTable('catalog_product_entity_media_gallery_value_to_entity');
$imageFile = $connection->fetchOne(
$connection->select()
->from(['gallery' => $galleryTable], ['value'])
->joinInner(['link' => $linkTable], 'link.value_id = gallery.value_id', [])
->where('link.entity_id = ?', (int)$product->getId())
->order('gallery.value_id ASC')
->limit(1)
);
$imageUrl = '';
if ($imageFile) {
$localImage = BP . '/pub/media/catalog/product' . $imageFile;
if (is_file($localImage)) {
$imageHelper->setImageFile((string)$imageFile);
} else {
$imageUrl = 'https://ltsecurityinc.com/media/catalog/product' . $imageFile;
}
}
$productData[] = [
'id' => (int)$product->getId(),
'name' => (string)$product->getName(),
'sku' => (string)$product->getSku(),
'url' => (string)$product->getProductUrl(),
'image' => $imageUrl ?: $imageHelper->resize(86, 86)->getUrl(),
'price' => $this->priceCurrency->format((float)$product->getFinalPrice(), false),
'in_stock' => $inStock,
'add_url' => $this->_url->getUrl('checkout/cart/add', ['product' => (int)$product->getId()])
];
}
return $result->setData([
'suggestions' => $this->getSuggestions($term, (int)$store->getId(), $productData),
'products' => $productData,
'total' => $total,
'search_url' => $this->_url->getUrl('catalogsearch/result', ['q' => $term])
]);
}
private function getSuggestions(string $term, int $storeId, array $products): array
{
$suggestions = [];
$this->appendSuggestion($suggestions, $term);
$queries = $this->queryCollectionFactory->create();
$queries->setStoreId($storeId)->setQueryFilter($term)->setPageSize(8);
foreach ($queries as $query) {
$this->appendSuggestion($suggestions, (string)$query->getQueryText());
}
$matchedCategories = $this->categoryCollectionFactory->create();
$matchedCategories->setStoreId($storeId)
->addAttributeToSelect(['name', 'path', 'level'])
->addAttributeToFilter('is_active', 1)
->addAttributeToFilter('name', ['like' => '%' . addcslashes($term, '%_') . '%'])
->setPageSize(5);
foreach ($matchedCategories as $category) {
$this->appendSuggestion($suggestions, (string)$category->getName());
if (count($suggestions) >= 8) {
break;
}
$children = $this->categoryCollectionFactory->create();
$children->setStoreId($storeId)
->addAttributeToSelect(['name', 'level'])
->addAttributeToFilter('is_active', 1)
->addFieldToFilter('path', ['like' => '%/' . (int)$category->getId() . '/%'])
->addFieldToFilter('level', ['lteq' => (int)$category->getLevel() + 2])
->setPageSize(8);
foreach ($children as $child) {
$name = (string)$child->getName();
$label = stripos($name, $term) === false ? $term . ' ' . $name : $name;
$this->appendSuggestion($suggestions, $label);
if (count($suggestions) >= 8) {
break 2;
}
}
}
foreach ($products as $product) {
$this->appendSuggestion($suggestions, (string)$product['name']);
if (count($suggestions) >= 8) {
break;
}
}
return array_slice(array_values($suggestions), 0, 8);
}
private function appendSuggestion(array &$suggestions, string $label): void
{
$label = trim(preg_replace('/\s+/', ' ', $label) ?: '');
if ($label === '') {
return;
}
$key = mb_strtolower($label);
if (!isset($suggestions[$key])) {
$suggestions[$key] = ['title' => $label];
}
}
}