ltsecurityinc安防产品在线商城代码

This commit is contained in:
2026-09-14 17:47:10 +08:00
parent 57d8444c15
commit 6a3c9c5bd8
14539 changed files with 1775310 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Block;
use Amasty\Sorting\Helper\Data;
use Magento\CatalogSearch\Block\Result as Subject;
use Magento\Framework\Registry;
class Result
{
/**
* @var Data
*/
private $helper;
/**
* @var Registry
*/
private $registry;
public function __construct(Data $helper, Registry $registry)
{
$this->helper = $helper;
$this->registry = $registry;
}
/**
* @param Subject $result
*
* @return Subject
*/
public function afterSetListOrders(Subject $result)
{
$searchSortings = $this->helper->getSearchSorting();
// getting first default sorting
$sortBy = array_shift($searchSortings);
$result->getListBlock()->setDefaultSortBy(
$sortBy
);
$this->registry->unregister(Data::SEARCH_SORTING);
$this->registry->register(Data::SEARCH_SORTING, true);
return $result;
}
}
+118
View File
@@ -0,0 +1,118 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog;
use Amasty\Sorting\Model\Method\IsMethodDisplayed;
use Amasty\Sorting\Model\MethodProvider;
use Amasty\Sorting\Model\Source\SortOptions;
use Amasty\Sorting\Model\SortingAdapterFactory;
use Magento\Catalog\Model\Config as CatalogEavConfig;
use Magento\Framework\View\LayoutInterface;
class Config
{
/**
* @var MethodProvider
*/
private $methodProvider;
/**
* @var SortingAdapterFactory
*/
private $adapterFactory;
/**
* @var LayoutInterface
*/
private $layout;
/**
* @var SortOptions
*/
private $sortOptions;
/**
* @var IsMethodDisplayed
*/
private $isMethodDisplayed;
public function __construct(
MethodProvider $methodProvider,
SortingAdapterFactory $adapterFactory,
LayoutInterface $layout,
SortOptions $sortOptions,
IsMethodDisplayed $isMethodDisplayed
) {
$this->methodProvider = $methodProvider;
$this->adapterFactory = $adapterFactory;
$this->layout = $layout;
$this->sortOptions = $sortOptions;
$this->isMethodDisplayed = $isMethodDisplayed;
}
/**
* Retrieve Attributes array used for sort by
*
* @param CatalogEavConfig $subject
* @param array $options
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetAttributesUsedForSortBy(CatalogEavConfig $subject, array $options): array
{
foreach ($options as $key => $option) {
if (!$this->isMethodDisplayed->execute($key)) {
unset($options[$key]);
}
}
return $this->addNewOptions($options);
}
/**
* @param array $options
* @return array
*/
public function addNewOptions(array $options): array
{
$methods = $this->methodProvider->getMethods();
foreach ($methods as $methodObject) {
$code = $methodObject->getMethodCode();
if ($this->isMethodDisplayed->execute($code) && !isset($options[$code])) {
$options[$code] = $this->adapterFactory->create(['methodModel' => $methodObject]);
}
}
return $options;
}
/**
* Retrieve Attributes Used for Sort by as array
* key = code, value = name
*
* @param CatalogEavConfig $subject
* @param array $options
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetAttributeUsedForSortByArray(CatalogEavConfig $subject, array $options): array
{
if (!$this->isMethodDisplayed->execute('position')) {
unset($options['position']);
}
$options = $this->sortOptions->execute($options);
if (count($options) == 0 && !$this->layout->getBlock('search.result')) {
$options[] = '';
}
return $options;
}
}
@@ -0,0 +1,56 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Helper\Product;
use Amasty\Sorting\Helper\Data;
use Magento\Framework\App\RequestInterface;
use Magento\Catalog\Helper\Product\ProductList as Subject;
class ProductList
{
/**
* @var Data
*/
private $helper;
/**
* @var RequestInterface
*/
private $request;
/**
* @var array
*/
private $searchModules = [
'catalogsearch'
];
public function __construct(
Data $helper,
RequestInterface $request
) {
$this->helper = $helper;
$this->request = $request;
}
/**
* @param Subject $subject
* @param $sortBy
* @return string
*/
public function afterGetDefaultSortField(Subject $subject, $sortBy)
{
if (in_array($this->request->getModuleName(), $this->searchModules)) {
$searchSortings = $this->helper->getSearchSorting();
// getting first default sorting
$sortBy = array_shift($searchSortings);
}
return $sortBy;
}
}
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Model\Category;
use Amasty\Sorting\Model\Method\IsMethodDisplayed;
use Amasty\Sorting\Model\Source\SortOptions;
use Magento\Catalog\Model\Category;
class SortAvailableOptions
{
/**
* @var SortOptions
*/
private $sortOptions;
/**
* @var IsMethodDisplayed
*/
private $isMethodDisplayed;
public function __construct(
SortOptions $sortOptions,
IsMethodDisplayed $isMethodDisplayed
) {
$this->sortOptions = $sortOptions;
$this->isMethodDisplayed = $isMethodDisplayed;
}
/**
* @param Category $subject
* @param array $options
* @return array
* @see \Magento\Catalog\Model\Category::getAvailableSortBy
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function afterGetAvailableSortBy(Category $subject, ?array $options): ?array
{
if ($options) {
if (!$this->isMethodDisplayed->execute('position')) {
unset($options['position']);
}
$options = array_flip($this->sortOptions->execute(array_flip($options)));
}
return $options;
}
}
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Model\ResourceModel\Product\Attribute;
use Amasty\Sorting\Model\Elasticsearch\IsElasticSort;
use Amasty\Sorting\Model\Method\GetAttributeCodesForSorting;
use Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection as AttributeCollection;
use Magento\Framework\DB\Select;
class Collection
{
/**
* @var IsElasticSort
*/
private $isElasticSort;
/**
* @var GetAttributeCodesForSorting
*/
private $getAttributeCodesForSorting;
public function __construct(
IsElasticSort $isElasticSort,
GetAttributeCodesForSorting $getAttributeCodesForSorting
) {
$this->isElasticSort = $isElasticSort;
$this->getAttributeCodesForSorting = $getAttributeCodesForSorting;
}
/**
* @param AttributeCollection $subject
* @param AttributeCollection $result
* @return AttributeCollection
*/
public function afterAddToIndexFilter($subject, $result)
{
if ($this->isElasticSort->execute(true)) {
$parts = $result->getSelect()->getPart(Select::WHERE);
$conditions = array_pop($parts);
$newCondition = $result->getConnection()->quoteInto(
'main_table.attribute_code IN (?)',
$this->getAttributeCodesForSorting->execute()
);
$conditions = str_replace(
'additional_table.is_searchable',
$newCondition . ' OR additional_table.is_searchable',
$conditions
);
$parts[] = $conditions;
$result->getSelect()->setPart(Select::WHERE, $parts);
}
return $result;
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Framework\DB\Select;
class PreventDoubleSort
{
/**
* Prevent double sorting by some attribute.
* Need on some cases with MySQL search engine.
* @see Collection::addAttributeToSort
*/
public function aroundAddAttributeToSort(
Collection $collection,
callable $proceed,
string $attribute,
string $dir = Collection::SORT_ORDER_ASC
): Collection {
if (!$collection->getFlag($this->getFlagName($attribute))
|| $this->isNeedForce($collection, $attribute)
) {
$collection->setFlag($this->getFlagName($attribute), true);
$proceed($attribute, $dir);
}
return $collection;
}
private function getFlagName(string $attribute): string
{
return sprintf('sorted_by_%s_attribute', $attribute);
}
/**
* We can skip flag check in case when order not appeared in select,
* because for search engines different MySQL check for double sorting added after setOrder trigger
* from fulltext collection.
*/
private function isNeedForce(Collection $collection, string $attribute): bool
{
$orders = $collection->getSelect()->getPart(Select::ORDER);
foreach ($orders as $order) {
if ($order instanceof \Zend_Db_Expr) {
$order = $order->__toString();
$expr = '/(.*\W)(' . Select::SQL_ASC . '|' . Select::SQL_DESC . ')\b/si';
preg_match($expr, $order, $matches);
if ($matches) {
$orderParts = trim($matches[1]);
} else {
$orderParts = trim($order);
}
} elseif (is_array($order) && isset($order[0])) {
$orderParts = explode('.', $order[0]);
}
$orderField = $orderParts[1] ?? $orderParts[0] ?? null;
if ($orderField === $attribute) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation;
use Amasty\Sorting\Model\Elasticsearch\ApplierFlag;
use Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation;
class PreventPriceSortingOnMysql
{
/**
* @var ApplierFlag
*/
private $applierFlag;
public function __construct(ApplierFlag $applierFlag)
{
$this->applierFlag = $applierFlag;
}
public function afterIsUsingPriceIndex(ProductLimitation $subject, bool $result): bool
{
if ($this->applierFlag->get()) {
$result = false;
}
return $result;
}
}
@@ -0,0 +1,232 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Product;
use Amasty\Sorting\Model\Elasticsearch\IsElasticSort;
use Amasty\Sorting\Model\Method\ApplyGlobalSorting;
use Amasty\Sorting\Model\MethodProvider;
use Amasty\Sorting\Model\ResourceModel\Method\Image as ImageMethodResource;
use Amasty\Sorting\Model\ResourceModel\Method\Instock as InstockMethodResource;
use Amasty\Sorting\Model\SortingAdapterFactory;
use Magento\Framework\DB\Select;
use Magento\Framework\Search\Adapter\Mysql\TemporaryStorage;
/**
* Plugin Collection
* plugin name: Amasty_Sorting::SortingMethodsProcessor
* type: \Magento\Catalog\Model\ResourceModel\Product\Collection
*/
class Collection
{
public const PROCESS_FLAG = 'amsort_process';
/**
* @var MethodProvider
*/
private $methodProvider;
/**
* @var SortingAdapterFactory
*/
private $adapterFactory;
/**
* @var ImageMethodResource
*/
private $imageMethod;
/**
* @var InstockMethodResource
*/
private $stockMethod;
/**
* @var array
*/
private $skipAttributes = [];
/**
* @var ApplyGlobalSorting
*/
private $applyGlobalSorting;
/**
* @var IsElasticSort
*/
private $isElasticSort;
/**
* @var bool
*/
private $isFulltextCollection;
public function __construct(
MethodProvider $methodProvider,
ImageMethodResource $imageMethod,
InstockMethodResource $stockMethod,
SortingAdapterFactory $adapterFactory,
ApplyGlobalSorting $applyGlobalSorting,
IsElasticSort $isElasticSort,
bool $isFulltextCollection = false
) {
$this->methodProvider = $methodProvider;
$this->adapterFactory = $adapterFactory;
$this->imageMethod = $imageMethod;
$this->stockMethod = $stockMethod;
$this->applyGlobalSorting = $applyGlobalSorting;
$this->isElasticSort = $isElasticSort;
$this->isFulltextCollection = $isFulltextCollection;
}
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $subject
* @param string $attribute
* @param string $dir 'ASC'|'DESC'
*
* @return array
*/
public function beforeSetOrder($subject, $attribute, $dir = Select::SQL_DESC)
{
$subject->setFlag(self::PROCESS_FLAG, true);
$this->applyHighPriorityOrders($subject, $dir);
$flagName = $this->getFlagName($attribute);
if ($subject->getFlag($flagName)) {
if ($this->isElasticSort()) {
$this->skipAttributes[] = $flagName;
} else {
// attribute already used in sorting; disable double sorting by renaming attribute into not existing
$attribute .= '_ignore';
}
} else {
$method = $this->methodProvider->getMethodByCode($attribute);
if ($method) {
$method->applyCustomAttribute($subject, $dir);
if (!$this->isElasticSort()) {
$method->apply($subject, $dir);
}
$attribute = $method->getAlias();
}
if (!$this->isElasticSort()) {
if ($attribute == 'relevance' && !$subject->getFlag($this->getFlagName('am_relevance'))) {
$this->addRelevanceSorting($subject, $dir);
$attribute = 'am_relevance';
}
if ($attribute == 'price') {
$subject->addOrder($attribute, $dir);
$attribute .= '_ignore';
}
}
$subject->setFlag($flagName, true);
}
$subject->setFlag(self::PROCESS_FLAG, false);
return [$attribute, $dir];
}
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $subject
* @param callable $proceed
* @param string $attribute
* @param string $dir
* @return mixed
*/
public function aroundSetOrder($subject, callable $proceed, $attribute, $dir = Select::SQL_DESC)
{
$flagName = $this->getFlagName($attribute);
if (!in_array($flagName, $this->skipAttributes)) {
$proceed($attribute, $dir);
}
return $subject;
}
private function getFlagName($attribute)
{
if ($attribute == 'price_asc' || $attribute == 'price_desc') {
$attribute = 'price';
}
if (is_string($attribute)) {
return 'sorted_by_' . $attribute;
}
return 'amasty_sorting';
}
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
* @param string $dir
*/
private function applyHighPriorityOrders($collection, $dir)
{
if (!$collection->getFlag($this->getFlagName('high'))) {
$collection->setFlag($this->getFlagName('high'), true);
if ($this->isElasticSort()) {
if ($this->imageMethod->isMethodActive($collection)) {
$collection->setOrder('non_images_last', Select::SQL_DESC);
}
if ($this->stockMethod->isMethodActive($collection)) {
$collection->setOrder('out_of_stock_last', Select::SQL_DESC);
}
} else {
$this->stockMethod->apply($collection, $dir);
$this->imageMethod->apply($collection, $dir);
}
$this->applyGlobalSorting->execute($collection);
}
}
/**
* @param \Magento\Catalog\Model\ResourceModel\Product\Collection $collection
*/
private function addRelevanceSorting($collection)
{
$collection->getSelect()->columns(['am_relevance' => new \Zend_Db_Expr(
'search_result.'. TemporaryStorage::FIELD_SCORE
)]);
$collection->addExpressionAttributeToSelect('am_relevance', 'am_relevance', []);
// remove last item from columns because e.am_relevance from addExpressionAttributeToSelect not exist
$columns = $collection->getSelect()->getPart(Select::COLUMNS);
array_pop($columns);
$collection->getSelect()->setPart(Select::COLUMNS, $columns);
$collection->setFlag($this->getFlagName('am_relevance'), true);
}
/**
* @param $subject
* @param $attribute
* @param string $dir
* @return array
*/
public function beforeAddOrder($subject, $attribute, $dir = Select::SQL_DESC)
{
if (!$subject->getFlag(self::PROCESS_FLAG)) {
$result = $this->beforeSetOrder($subject, $attribute, $dir);
}
return $result ?? [$attribute, $dir];
}
/**
* @param $subject
* @param callable $proceed
* @param $attribute
* @param string $dir
* @return mixed
*/
public function aroundAddOrder($subject, callable $proceed, $attribute, $dir = Select::SQL_DESC)
{
return $this->aroundSetOrder($subject, $proceed, $attribute, $dir);
}
private function isElasticSort(): bool
{
return $this->isFulltextCollection && $this->isElasticSort->execute();
}
}
@@ -0,0 +1,68 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Product;
use Amasty\Sorting\Model\Logger as AmastyLogger;
use Amasty\Sorting\Model\MethodProvider;
use Magento\Catalog\Block\Product\ListProduct as NativeList;
use Magento\Catalog\Block\Product\ProductList\Toolbar;
use Magento\Eav\Model\Entity\Collection\AbstractCollection;
class ListProduct
{
/**
* @var MethodProvider
*/
private $methodProvider;
/**
* @var AmastyLogger
*/
private $logger;
public function __construct(MethodProvider $methodProvider, AmastyLogger $logger)
{
$this->methodProvider = $methodProvider;
$this->logger = $logger;
}
/**
* @param NativeList $subject
* @param array $identities
*
* @return array
*/
public function afterGetIdentities(NativeList $subject, $identities)
{
/** @var Toolbar $toolbarBlock */
$toolbarBlock = $subject->getLayout()->getBlock('product_list_toolbar');
if ($toolbarBlock
&& in_array(
$toolbarBlock->getCurrentOrder(),
array_keys($this->methodProvider->getIndexedMethods())
)
) {
$identities[] = 'sorted_by_' . $toolbarBlock->getCurrentOrder();
}
return $identities;
}
/**
* @param NativeList $subject
* @param AbstractCollection $result
*
* @return AbstractCollection
*/
public function afterGetLoadedProductCollection(NativeList $subject, $result)
{
$this->logger->logCollectionQuery($result);
return $result;
}
}
@@ -0,0 +1,174 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Catalog\Product\ProductList;
use Amasty\Sorting\Helper\Data;
use Amasty\Sorting\Model\Catalog\Toolbar\GetDefaultDirection;
use Amasty\Sorting\Model\Method\ApplyGlobalSorting;
use Amasty\Sorting\Model\Method\IsAvailableForSorting;
use Amasty\Sorting\Model\ResourceModel\Method\Image as ImageMethod;
use Amasty\Sorting\Model\ResourceModel\Method\Instock as InstockMethod;
use Magento\Catalog\Model\Product\ProductList\Toolbar as ToolbarModel;
use Magento\Catalog\Model\ResourceModel\Product\Collection as ProductCollection;
use Magento\Framework\Registry;
class Toolbar
{
/**
* @var Data
*/
private $helper;
/**
* @var ToolbarModel
*/
private $toolbarModel;
/**
* @var ImageMethod
*/
private $imageMethod;
/**
* @var InstockMethod
*/
private $stockMethod;
/**
* @var Registry
*/
private $registry;
/**
* @var GetDefaultDirection
*/
private $getDefaultDirection;
/**
* @var ApplyGlobalSorting
*/
private $applyGlobalSorting;
/**
* @var IsAvailableForSorting
*/
private $isAvailableForSorting;
public function __construct(
Data $helper,
ToolbarModel $toolbarModel,
ImageMethod $imageMethod,
InstockMethod $stockMethod,
Registry $registry,
GetDefaultDirection $getDefaultDirection,
ApplyGlobalSorting $applyGlobalSorting,
IsAvailableForSorting $isAvailableForSorting
) {
$this->helper = $helper;
$this->toolbarModel = $toolbarModel;
$this->imageMethod = $imageMethod;
$this->stockMethod = $stockMethod;
$this->registry = $registry;
$this->getDefaultDirection = $getDefaultDirection;
$this->applyGlobalSorting = $applyGlobalSorting;
$this->isAvailableForSorting = $isAvailableForSorting;
}
/**
* @param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
* @param string $dir
*
* @return string
*/
public function afterGetCurrentDirection($subject, $dir)
{
$defaultDir = $this->getDefaultDirection->execute($subject->getCurrentOrder());
$subject->setDefaultDirection($defaultDir);
if (!$this->toolbarModel->getDirection()
|| $this->shouldSetDirection($subject->getCurrentOrder())
) {
$dir = $defaultDir;
}
return $dir;
}
/**
* @param string $order
*
* @return bool
*/
private function shouldSetDirection($order)
{
return in_array($order, GetDefaultDirection::ALWAYS_DESC)
|| in_array($order, GetDefaultDirection::ALWAYS_ASC);
}
/**
* @param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
* @param ProductCollection $collection
*
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function beforeSetCollection($subject, $collection)
{
if ($collection instanceof ProductCollection && !$this->isFulltextCollection($collection)) {
// no image sorting will be the first or the second (after stock). LIFO queue
$this->imageMethod->apply($collection);
// in stock sorting will be first, as the method always moves it's paremater first. LIFO queue
$this->stockMethod->apply($collection);
$this->applyGlobalSorting->execute($collection);
}
return [$collection];
}
/**
* @param \Magento\Catalog\Block\Product\ProductList\Toolbar $subject
* @param \Magento\Catalog\Block\Product\ProductList\Toolbar $result
*
* @return \Magento\Catalog\Block\Product\ProductList\Toolbar
*/
public function afterSetCollection($subject, $result)
{
$collection = $subject->getCollection();
if ($collection instanceof ProductCollection) {
$this->applyOrdersFromConfig($collection);
}
return $result;
}
private function applyOrdersFromConfig(ProductCollection $collection): void
{
if ($this->registry->registry(Data::SEARCH_SORTING)) {
$defaultSortings = $this->helper->getSearchSorting();
} else {
$defaultSortings = $this->helper->getCategorySorting();
}
// first sorting must be setting by magento as default sorting
array_shift($defaultSortings);
foreach ($defaultSortings as $defaultSorting) {
if ($this->isAvailableForSorting->execute($defaultSorting)) {
$dir = $this->getDefaultDirection->execute($defaultSorting);
$collection->setOrder($defaultSorting, $dir);
}
}
}
private function isFulltextCollection(ProductCollection $collection): bool
{
return $collection instanceof \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection
|| $collection instanceof \Amasty\Shopby\Model\ResourceModel\Fulltext\Collection
|| $collection instanceof \Amasty\ShopbyLite\Model\ResourceModel\Fulltext\Collection;
}
}
@@ -0,0 +1,36 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\CatalogInventory\Model\Source;
class Stock
{
/**
* @param \Magento\CatalogInventory\Model\Source\Stock $subject
* @param \Closure $proceed
* @param \Magento\Eav\Model\Entity\Collection\AbstractCollection $collection
* @param string $dir
*
* @return $this
*/
public function aroundAddValueSortToCollection(
$subject,
$proceed,
$collection,
$dir
) {
// fix magento bug. getting full table name
$collection->getSelect()->joinLeft(
['stock_item_table' => $collection->getResource()->getTable('cataloginventory_stock_item')],
"e.entity_id=stock_item_table.product_id",
[]
);
$collection->getSelect()->order("stock_item_table.qty $dir");
return $subject;
}
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\CatalogSearch\Model\ResourceModel\Fulltext\Collection;
class ApplySorting extends \Amasty\Sorting\Plugin\Catalog\Product\Collection
{
}
@@ -0,0 +1,93 @@
<?php
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Elasticsearch\Model\Adapter\BatchDataMapper;
use Amasty\Sorting\Helper\Data;
use Amasty\Sorting\Model\Elasticsearch\Adapter\DataMapperInterface;
use Amasty\Sorting\Model\Elasticsearch\Adapter\IndexedDataMapper;
use Amasty\Sorting\Model\Elasticsearch\SkuRegistry;
use Magento\Elasticsearch\Model\Adapter\BatchDataMapper\ProductDataMapper;
class AdditionalProductDataMapper
{
/**
* @var SkuRegistry
*/
private $skuRegistry;
/**
* @var Data
*/
private $helper;
/**
* @var DataMapperInterface[]
*/
private $dataMappers;
public function __construct(
SkuRegistry $skuRegistry,
Data $helper,
array $dataMappers = []
) {
$this->skuRegistry = $skuRegistry;
$this->helper = $helper;
$this->dataMappers = $dataMappers;
}
/**
* Prepare index data for using in search engine metadata.
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
* @param ProductDataMapper $subject
* @param callable $proceed
* @param array $documentData
* @param $storeId
* @param array $context
* @return array
*/
public function afterMap(
$subject,
array $result,
array $documentData,
$storeId,
$context = []
) {
$productIds = array_keys($result);
if ($this->helper->getOutOfStockLast($storeId)) {
/** load sku relations needed in @see \Amasty\Sorting\Model\Elasticsearch\Adapter\DataMapper\Stock */
$this->skuRegistry->save($productIds);
}
foreach ($result as $productId => $document) {
$context['document'] = $document;
foreach ($this->dataMappers as $mapper) {
if ($mapper instanceof DataMapperInterface && $mapper->isAllowed($storeId)) {
if ($mapper instanceof IndexedDataMapper) {
$mapper->loadEntities($storeId, $productIds);
}
//@codingStandardsIgnoreLine
$document = array_merge($document, $mapper->map($productId, $document, $storeId, $context));
}
}
$result[$productId] = $document;
}
$this->clearData($storeId);
return $result;
}
private function clearData(int $storeId): void
{
$this->skuRegistry->clear();
foreach ($this->dataMappers as $mapper) {
if ($mapper instanceof IndexedDataMapper && $mapper->isAllowed($storeId)) {
$mapper->clearValues();
}
}
}
}
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Elasticsearch\Model\Adapter\FieldMapper\Product;
use Amasty\Sorting\Model\Method\GetAttributeCodesForSorting;
use Magento\Elasticsearch\Model\Adapter\FieldMapper\Product\AttributeAdapter as NativeAttributeAdapter;
class AttributeAdapter
{
/**
* @var GetAttributeCodesForSorting
*/
private $getAttributeCodesForSorting;
public function __construct(GetAttributeCodesForSorting $getAttributeCodesForSorting)
{
$this->getAttributeCodesForSorting = $getAttributeCodesForSorting;
}
/**
* @param NativeAttributeAdapter $subject
* @param bool $result
* @return bool
*/
public function afterIsSortable($subject, $result)
{
if (!$result && in_array($subject->getAttributeCode(), $this->getAttributeCodesForSorting->execute())) {
$result = true;
}
return $result;
}
}
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier;
use Amasty\Sorting\Model\Elasticsearch\ApplierFlag;
use Magento\Elasticsearch\Model\ResourceModel\Fulltext\Collection\SearchResultApplier;
class SetApplierFlag
{
/**
* @var ApplierFlag
*/
private $applierFlag;
public function __construct(ApplierFlag $applierFlag)
{
$this->applierFlag = $applierFlag;
}
public function aroundApply(SearchResultApplier $subject, callable $proceed): void
{
$this->applierFlag->enable();
$proceed();
$this->applierFlag->disable();
}
}
@@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\InventoryReservations\Model;
use Amasty\Base\Model\Serializer;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
use Magento\Framework\ObjectManagerInterface;
use Magento\Framework\Validation\ValidationException;
use Magento\InventoryReservationsApi\Model\ReservationInterface;
use Magento\Sales\Api\Data\OrderInterface;
use Magento\Sales\Api\OrderRepositoryInterface;
use Psr\Log\LoggerInterface;
class AppendReservationsPlugin
{
/**
* @var Serializer
*/
private $serializer;
/**
* @var OrderRepositoryInterface
*/
private $orderRepository;
/**
* @var ObjectManagerInterface
*/
private $objectManager;
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(
Serializer $serializer,
OrderRepositoryInterface $orderRepository,
ObjectManagerInterface $objectManager,
LoggerInterface $logger
) {
$this->serializer = $serializer;
$this->orderRepository = $orderRepository;
$this->objectManager = $objectManager;
$this->logger = $logger;
}
/**
* @param \Magento\InventoryReservations\Model\AppendReservations $subject
* @param array $reservations
* @return array
*/
public function beforeExecute($subject, array $reservations)
{
$parentReservations = [];
if ($reservations) {
$reservation = reset($reservations);
try {
$metadata = $this->unserialize($reservation->getMetadata());
if (isset($metadata['object_type'])
&& !empty($metadata['object_id'])
&& $metadata['object_type'] == 'order'
) {
$order = $this->orderRepository->get($metadata['object_id']);
foreach ($reservations as $reservation) {
if ($newReservation = $this->createParentReservation($order, $reservation)) {
$parentReservations[] = $newReservation;
}
}
}
} catch (\InvalidArgumentException $e) {
$this->logger->error($e->getMessage());
}
}
return [array_merge($reservations, $parentReservations)];
}
/**
* @param OrderInterface $order
* @param ReservationInterface $reservation
* @return bool|ReservationInterface
*/
private function createParentReservation($order, $reservation)
{
$parentReservation = false;
foreach ($order->getItems() as $orderItem) {
if ($orderItem->getParentItemId()
&& $orderItem->getParentItem()->getProductType() == Configurable::TYPE_CODE
&& $orderItem->getParentItem()->getProduct()
&& $orderItem->getSku() == $reservation->getSku()
) {
try {
$parentReservation = $this->getReservationBuilder()
->setSku($orderItem->getParentItem()->getProduct()->getSku())
->setQuantity((float)$reservation->getQuantity())
->setStockId($reservation->getStockId())
->setMetadata($reservation->getMetadata())
->build();
break;
} catch (ValidationException $e) {
$this->logger->error($e->getMessage());
$parentReservation = false;
continue;
}
}
}
return $parentReservation;
}
/**
* @param $data
* @return array|bool|float|int|string|null
* @throws \InvalidArgumentException
*/
private function unserialize($data)
{
return $this->serializer->unserialize($data);
}
/**
* @return \Magento\InventoryReservationsApi\Model\ReservationBuilderInterface
*/
private function getReservationBuilder()
{
return $this->objectManager->get(
\Magento\InventoryReservationsApi\Model\ReservationBuilderInterface::class
);
}
}
@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Review\Model\Review;
use Amasty\Sorting\Api\ProductReviewLinkProcessorInterface;
use Amasty\Sorting\Helper\Data;
use Magento\CatalogSearch\Model\Indexer\Fulltext\Processor as FulltextIndexer;
use Magento\Review\Model\Review;
class SortByReview
{
/**
* @var ProductReviewLinkProcessorInterface
*/
private $productReviewLinkProcessor;
/**
* @var FulltextIndexer
*/
private $fulltextIndexer;
/**
* @var Data
*/
private $moduleHelper;
public function __construct(
ProductReviewLinkProcessorInterface $productReviewLinkProcessor,
FulltextIndexer $fulltextIndexer,
Data $moduleHelper
) {
$this->productReviewLinkProcessor = $productReviewLinkProcessor;
$this->fulltextIndexer = $fulltextIndexer;
$this->moduleHelper = $moduleHelper;
}
public function afterAggregate(Review $subject, Review $review): Review
{
if ($review->getEntityId() === $review->getEntityIdByCode(Review::ENTITY_PRODUCT_CODE)) {
$productId = (int) $review->getEntityPkValue();
$this->productReviewLinkProcessor->create($productId, (int) $review->getId());
if ($this->moduleHelper->isElasticSort(true)) {
$this->fulltextIndexer->reindexRow($productId, false);
}
}
return $review;
}
}
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
/**
* @author Amasty Team
* @copyright Copyright (c) Amasty (https://www.amasty.com)
* @package Improved Sorting for Magento 2
*/
namespace Amasty\Sorting\Plugin\Sorting\Block\Widget\Featured;
use Amasty\Sorting\Block\Widget\Featured;
use Amasty\Sorting\ViewModel\Helpers;
class SetViewModel
{
/**
* @var Helpers
*/
private $helpers;
public function __construct(Helpers $helpers)
{
$this->helpers = $helpers;
}
/**
* @param Featured $featuredWidget
*/
public function beforeToHtml(Featured $featuredWidget): void
{
$featuredWidget->setData('helpers', $this->helpers);
}
}