diff --git a/src/module-elasticsuite-catalog/Helper/ProductAttribute.php b/src/module-elasticsuite-catalog/Helper/ProductAttribute.php index 36cc774d9..4b2d1b62e 100644 --- a/src/module-elasticsuite-catalog/Helper/ProductAttribute.php +++ b/src/module-elasticsuite-catalog/Helper/ProductAttribute.php @@ -17,6 +17,8 @@ use Magento\Framework\App\Helper\Context; use Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory; use Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory as AttributeCollectionFactory; +use Magento\Framework\Locale\LocaleFormatter; +use Magento\Store\Model\ScopeInterface; /** * ElasticSuite product attributes helper. @@ -27,15 +29,103 @@ */ class ProductAttribute extends AbstractAttribute { + /** + * @var string Config path to determine if we should use display battern on frontend. + */ + const XML_PATH_FRONTEND_PRODUCT_DISPLAY_PATTERN_ENABLED + = 'smile_elasticsuite_catalogsearch_settings/catalogsearch/frontend_product_display_pattern_enabled'; + + /** + * @var string Attribute column containing pattern. + */ + const DISPLAY_PATTERN_COLUMN = 'display_pattern'; + + /** + * @var string Attribute column containing precision. + */ + const DISPLAY_PRECISION_COLUMN = 'display_precision'; + + /** + * @var string Default display pattern if not otherwise specified. + */ + const DEFAULT_DISPLAY_PATTERN = '%s'; + + /** + * @var string Round value to this many decimal places if not otherwise specified. + */ + const DEFAULT_DISPLAY_PRECISION = 2; + + /** + * @var int The maximum possible replacements for each pattern in each subject string. + */ + const REPLACEMENT_LIMIT = 1; + + /** + * @var \Magento\Framework\Locale\LocaleFormatter $localeFormatter + */ + protected $localeFormatter; + /** * Constructor. * * @param Context $context Helper context. * @param AttributeFactory $attributeFactory Factory used to create attributes. * @param AttributeCollectionFactory $collectionFactory Attribute collection factory. + * @param LocaleFormatter $localeFormatter Format numbers to a locale */ - public function __construct(Context $context, AttributeFactory $attributeFactory, AttributeCollectionFactory $collectionFactory) - { + public function __construct( + Context $context, + AttributeFactory $attributeFactory, + AttributeCollectionFactory $collectionFactory, + LocaleFormatter $localeFormatter + ) { + $this->localeFormatter = $localeFormatter; parent::__construct($context, $attributeFactory, $collectionFactory); } + + /** + * Is Display Pattern on Frontend Enabled ? + * + * @return bool + */ + public function isFrontendProductDisplayPatternEnabled(): bool + { + return (bool) $this->scopeConfig->getValue( + self::XML_PATH_FRONTEND_PRODUCT_DISPLAY_PATTERN_ENABLED, + ScopeInterface::SCOPE_STORE + ); + } + + /** + * Format Product Attribute Value with Display Pattern + * + * Value's stored as numeric (i.e `8` or `355`) and the attribute has a display pattern (i.e `% %s` or `%s mm`) + * will be formatted as `% 8` or `355 mm` + * + * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute Product Attribute to format + * @param int|float|string $value Product Attribute Value to format + * + * @return string Formatted string + */ + public function formatProductAttributeValueDisplayPattern($attribute, $value) + { + // Translate attribute pattern, or default, without variable. + // @codingStandardsIgnoreStart + $pattern = $attribute->getData(self::DISPLAY_PATTERN_COLUMN) + ? (string) __($attribute->getData(self::DISPLAY_PATTERN_COLUMN)) + : (string) self::DEFAULT_DISPLAY_PATTERN; + // @codingStandardsIgnoreEnd + + // Get attribute display precision or default. + // @codingStandardsIgnoreStart + $precision = is_numeric($attribute->getData(self::DISPLAY_PRECISION_COLUMN) ?? '') + ? (int) abs($attribute->getData(self::DISPLAY_PRECISION_COLUMN)) + : (int) self::DEFAULT_DISPLAY_PRECISION; + // @codingStandardsIgnoreEnd + + // Round value to precision and format to locale string. + $amount = (string) $this->localeFormatter->formatNumber(round((float) $value, $precision)); + // Insert number value into translated string. + return (string) preg_replace('/' . self::DEFAULT_DISPLAY_PATTERN . '/', $amount, $pattern, self::REPLACEMENT_LIMIT); + } } diff --git a/src/module-elasticsuite-catalog/Plugin/Catalog/Product/Compare/ListComparePlugin.php b/src/module-elasticsuite-catalog/Plugin/Catalog/Product/Compare/ListComparePlugin.php new file mode 100644 index 000000000..eb096ba21 --- /dev/null +++ b/src/module-elasticsuite-catalog/Plugin/Catalog/Product/Compare/ListComparePlugin.php @@ -0,0 +1,113 @@ + + * @copyright 2020 Smile + * @license Open Software License ("OSL") v. 3.0 + */ +namespace Smile\ElasticsuiteCatalog\Plugin\Catalog\Product\View; + +use Magento\Catalog\Api\ProductAttributeRepositoryInterface; +use Smile\ElasticsuiteCatalog\Helper\ProductAttribute; + +/** + * Catalog Product List Compare plugin. + * + * @category Smile + * @package Smile\ElasticsuiteCatalog + * @author Edward Crocombe + */ +class ListComparePlugin +{ + /** + * @var null|\Magento\Catalog\Api\Data\ProductAttributeInterface[] + */ + private $attributes; + + /** + * @var \Smile\ElasticsuiteCatalog\Helper\ProductAttribute + */ + private $productAttributeHelper; + + /** + * @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface $productAttributeRepository + */ + private $productAttributeRepository; + + /** + * Constructor. + * + * @param ProductAttribute $productAttributeHelper ElasticSuite product attributes helper. + * @param ProductAttributeRepositoryInterface $productAttributeRepository Formats numbers to a locale + */ + public function __construct( + ProductAttribute $productAttributeHelper, + ProductAttributeRepositoryInterface $productAttributeRepository + ) { + $this->productAttributeHelper = $productAttributeHelper; + $this->productAttributeRepository = $productAttributeRepository; + } + + /** + * Add display pattern for frontend display + * + * @param \Magento\Catalog\Block\Product\Compare\ListCompare $subject Plugin Subject + * @param \Magento\Framework\Phrase|string $result Plugin Result + * @param \Magento\Catalog\Model\Product $product Product + * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute Product Attribute + * + * @return \Magento\Framework\Phrase|string + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetProductAttributeValue( + \Magento\Catalog\Block\Product\Compare\ListCompare $subject, + $result, + $product, + $attribute + ) { + if (!$this->productAttributeHelper->isFrontendProductDisplayPatternEnabled()) { + return $result; + } + + $value = $attribute->getFrontend()->getValue($product); + if (is_numeric($value) && strlen($attribute->getData('display_pattern') ?? '') > 0) { + $result = $this->productAttributeHelper->formatProductAttributeValueDisplayPattern($attribute, $value); + } + + return $result; + } + + /** + * Retrieve Product Compare Attributes + * + * Default getAttributes retrieves columns from eav_attribute table only, + * both the display_pattern and display_precision values are on the catalog_eav_attribute table. + * + * @param \Magento\Catalog\Block\Product\Compare\ListCompare $subject Plugin Subject + * @param \Magento\Eav\Model\Entity\Attribute\AbstractAttribute[] $result Plugin Result + * + * @return \Magento\Catalog\Api\Data\ProductAttributeInterface[] + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetAttributes(\Magento\Catalog\Block\Product\Compare\ListCompare $subject, $result) + { + if (!$this->productAttributeHelper->isFrontendProductDisplayPatternEnabled()) { + return $result; + } + + if ($this->attributes === null) { + $this->attributes = []; + foreach (array_keys($result) as $attributeCode) { + $this->attributes[$attributeCode] = $this->productAttributeRepository->get($attributeCode); + } + } + + return $this->attributes; + } +} diff --git a/src/module-elasticsuite-catalog/Plugin/Catalog/Product/View/AttributesPlugin.php b/src/module-elasticsuite-catalog/Plugin/Catalog/Product/View/AttributesPlugin.php new file mode 100644 index 000000000..ef4a215d1 --- /dev/null +++ b/src/module-elasticsuite-catalog/Plugin/Catalog/Product/View/AttributesPlugin.php @@ -0,0 +1,80 @@ + + * @copyright 2020 Smile + * @license Open Software License ("OSL") v. 3.0 + */ +namespace Smile\ElasticsuiteCatalog\Plugin\Catalog\Product\View; + +use Smile\ElasticsuiteCatalog\Helper\ProductAttribute; + +/** + * Catalog Product View Attributes plugin. + * + * @category Smile + * @package Smile\ElasticsuiteCatalog + * @author Edward Crocombe + */ +class AttributesPlugin +{ + /** + * @var \Smile\ElasticsuiteCatalog\Helper\ProductAttribute + */ + private $productAttributeHelper; + + /** + * Constructor. + * + * @param ProductAttribute $productAttributeHelper ElasticSuite product attributes helper. + */ + public function __construct( + ProductAttribute $productAttributeHelper + ) { + $this->productAttributeHelper = $productAttributeHelper; + } + + /** + * Add display pattern for frontend display + * + * @param \Magento\Catalog\Block\Product\View\Attributes $subject Plugin Subject + * @param array $result Additional data + * @param string[] $excludeAttr Attribute Codes to exclude + * + * @return array Additional data + * @throws \Magento\Framework\Exception\LocalizedException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetAdditionalData(\Magento\Catalog\Block\Product\View\Attributes $subject, $result, array $excludeAttr = []) + { + if (!$this->productAttributeHelper->isFrontendProductDisplayPatternEnabled()) { + return $result; + } + + $product = $subject->getProduct(); + $attributes = $product->getAttributes(); + foreach ($attributes as $attribute) { + // If attribute is already in array, then isVisibleOnFrontend = `true`. + if (isset($result[$attribute->getAttributeCode()])) { + // @codingStandardsIgnoreStart + $value = isset($result[$attribute->getAttributeCode()]['value']) + ? $result[$attribute->getAttributeCode()]['value'] + : ''; + // @codingStandardsIgnoreEnd + + if (is_numeric($value) && strlen($attribute->getData('display_pattern') ?? '') > 0) { + $result[$attribute->getAttributeCode()]['value'] + = $this->productAttributeHelper->formatProductAttributeValueDisplayPattern($attribute, $value); + } + } + } + + return $result; + } +} diff --git a/src/module-elasticsuite-catalog/etc/adminhtml/system.xml b/src/module-elasticsuite-catalog/etc/adminhtml/system.xml index 1a1fd2b7a..5540707dc 100644 --- a/src/module-elasticsuite-catalog/etc/adminhtml/system.xml +++ b/src/module-elasticsuite-catalog/etc/adminhtml/system.xml @@ -75,6 +75,11 @@ Magento\Config\Model\Config\Source\Yesno + + + Magento\Config\Model\Config\Source\Yesno + + Magento\Config\Model\Config\Source\Yesno diff --git a/src/module-elasticsuite-catalog/etc/config.xml b/src/module-elasticsuite-catalog/etc/config.xml index 74424e032..e42c08e6c 100644 --- a/src/module-elasticsuite-catalog/etc/config.xml +++ b/src/module-elasticsuite-catalog/etc/config.xml @@ -38,6 +38,7 @@ 1 3 0 + 0 0 0 diff --git a/src/module-elasticsuite-catalog/etc/di.xml b/src/module-elasticsuite-catalog/etc/di.xml index 1b544d855..866329bd4 100644 --- a/src/module-elasticsuite-catalog/etc/di.xml +++ b/src/module-elasticsuite-catalog/etc/di.xml @@ -418,4 +418,20 @@ + + + + + + + + + + + + + + +