├── composer.json ├── registration.php ├── etc ├── adminhtml │ ├── routes.xml │ ├── menu.xml │ ├── events.xml │ └── system.xml ├── config.xml ├── frontend │ └── events.xml ├── module.xml ├── acl.xml ├── db_schema_whitelist.json ├── di.xml └── db_schema.xml ├── Model ├── Condition │ └── Sql │ │ ├── Expression.php │ │ └── Builder.php ├── ImageField.php ├── Source │ └── Config │ │ ├── Position.php │ │ ├── Store.php │ │ ├── LabelType.php │ │ ├── Type.php │ │ ├── Status.php │ │ └── CustomerGroup.php ├── Config.php ├── Rule │ ├── Condition │ │ ├── Combine.php │ │ └── Product.php │ └── DataProvider.php ├── ResourceModel │ ├── Rule │ │ └── Collection.php │ └── Rule.php ├── Indexer │ ├── Full.php │ └── Row.php └── Rule.php ├── view ├── adminhtml │ ├── layout │ │ ├── product_label_rule_edit.xml │ │ └── product_label_rule_index.xml │ ├── templates │ │ └── rule │ │ │ └── fieldset.phtml │ └── ui_component │ │ └── boolfly_label_rule_listing.xml └── frontend │ ├── layout │ └── catalog_product_view.xml │ ├── templates │ ├── label.phtml │ └── product │ │ └── label.phtml │ └── web │ └── css │ └── source │ └── _module.less ├── Controller └── Adminhtml │ ├── Image │ └── Upload.php │ ├── Rule │ ├── NewAction.php │ ├── Index.php │ ├── Delete.php │ ├── NewConditionHtml.php │ ├── Edit.php │ ├── MassDelete.php │ ├── MassStatus.php │ └── Save.php │ └── AbstractRule.php ├── Observer ├── AfterLoadProductCollection.php ├── AddLabelRuleData.php ├── AfterSaveRule.php ├── UpdateRuleAfterProductSave.php └── ProcessingImageUpload.php ├── Plugin └── Catalog │ └── Block │ ├── ProductPlugin.php │ └── Product │ └── ImagePlugin.php ├── Block ├── Label.php ├── Product │ └── Label.php └── Adminhtml │ └── Rule │ └── Conditions.php ├── Ui └── Component │ └── Listing │ └── Columns │ └── EditActions.php ├── README.md ├── Api └── Data │ └── RuleInterface.php ├── LICENSE.txt └── Helper └── Rule.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boolfly/module-product-label", 3 | "description": "Product Label Module", 4 | "require": { 5 | "php": ">=7.3 || >=8.0", 6 | "boolfly/module-base": "^1.0.0" 7 | }, 8 | "type": "magento2-module", 9 | "license": [ 10 | "OSL-3.0", 11 | "AFL-3.0" 12 | ], 13 | "autoload": { 14 | "files": [ 15 | "registration.php" 16 | ], 17 | "psr-4": { 18 | "Boolfly\\ProductLabel\\": "" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /registration.php: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Model/Condition/Sql/Expression.php: -------------------------------------------------------------------------------- 1 | _expression !== '' ? '(' . $this->_expression . ')' : ''; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 1 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /view/adminhtml/layout/product_label_rule_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /view/adminhtml/layout/product_label_rule_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Model/ImageField.php: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Image/Upload.php: -------------------------------------------------------------------------------- 1 | _forward('edit'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /etc/frontend/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/Index.php: -------------------------------------------------------------------------------- 1 | initAction()->_addBreadcrumb(__('Catalog'), __('Catalog')); 27 | $this->_view->getPage()->getConfig()->getTitle()->prepend(__('Manage Rules')); 28 | $this->_view->renderLayout(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /etc/adminhtml/events.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 |
15 | separator-top 16 | boolfly 17 | 18 | Boolfly_ProductLabel::config 19 | 20 | 21 | 22 | 23 | Magento\Config\Model\Config\Source\Yesno 24 | 25 | 26 |
27 |
28 |
-------------------------------------------------------------------------------- /Observer/AfterLoadProductCollection.php: -------------------------------------------------------------------------------- 1 | helperRule = $helperRule; 38 | } 39 | 40 | /** 41 | * @param Observer $observer 42 | * @throws \Exception 43 | */ 44 | public function execute(Observer $observer) 45 | { 46 | /** @var Collection $collection */ 47 | $collection = $observer->getEvent()->getData('collection'); 48 | $this->helperRule->addRuleIdsToCollection($collection); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Observer/AddLabelRuleData.php: -------------------------------------------------------------------------------- 1 | helperRule = $helperRule; 39 | } 40 | 41 | /** 42 | * @param Observer $observer 43 | * @throws \Exception 44 | */ 45 | public function execute(Observer $observer) 46 | { 47 | /** @var Product $product */ 48 | $product = $observer->getEvent()->getData('product'); 49 | if ($product instanceof Product) { 50 | $this->helperRule->addRuleIds($product); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Model/Source/Config/Position.php: -------------------------------------------------------------------------------- 1 | 'top-left', 'label' => __('Top-Left')], 31 | ['value' => 'top-right', 'label' => __('Top-Right')], 32 | ['value' => 'bot-left', 'label' => __('Bottom-Left')], 33 | ['value' => 'bot-right', 'label' => __('Bottom-Right')] 34 | ]; 35 | 36 | return $options; 37 | } 38 | 39 | /** 40 | * Get options in "key-value" format 41 | * 42 | * @return array 43 | */ 44 | public function toArray() 45 | { 46 | return [ 47 | 'top-left' => __('Top-Left'), 48 | 'top-right' => __('Top-Right'), 49 | 'bottom-left' => __('Bottom-Left'), 50 | 'bottom-right' => __('Bottom-Right') 51 | ]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Observer/AfterSaveRule.php: -------------------------------------------------------------------------------- 1 | indexerFull = $indexerFull; 40 | } 41 | 42 | /** 43 | * Execute event 44 | * 45 | * @param Observer $observer 46 | * @throws \Exception 47 | */ 48 | public function execute(Observer $observer) 49 | { 50 | $rule = $observer->getEvent()->getData('label_rule'); 51 | if ($rule instanceof RuleInterface) { 52 | $this->indexerFull->setRule($rule); 53 | $this->indexerFull->execute(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /view/frontend/templates/label.phtml: -------------------------------------------------------------------------------- 1 | getGroupRule(); 12 | ?> 13 | 14 | $rules) :?> 15 | 16 | 18 | 20 | isUseImageInList()) :?> 21 | <?= /* @escapeNotVerified */ $rule->getTitle()?> 24 | 25 | 26 | getCategoryText()?> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /view/frontend/templates/product/label.phtml: -------------------------------------------------------------------------------- 1 | getGroupRule(); 12 | ?> 13 | 14 | $rules) :?> 15 | 16 | 18 | 20 | isUseImageInProduct()) :?> 21 | <?= /* @escapeNotVerified */ $rule->getTitle()?> 24 | 25 | 26 | getProductText()?> 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Model/Config.php: -------------------------------------------------------------------------------- 1 | scopeConfig = $scopeConfig; 41 | } 42 | 43 | /** 44 | * Get Configuration 45 | * 46 | * @param $path 47 | * @return mixed 48 | */ 49 | public function getConfig($path) 50 | { 51 | return $this->scopeConfig->getValue($path, ScopeInterface::SCOPE_STORES); 52 | } 53 | 54 | /** 55 | * Enable Mega menu 56 | * 57 | * @return boolean 58 | */ 59 | public function isEnable() 60 | { 61 | return $this->scopeConfig->isSetFlag(self::XML_PATH_PRODUCT_LABEL_ENABLE, ScopeInterface::SCOPE_STORES); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Model/Source/Config/Store.php: -------------------------------------------------------------------------------- 1 | systemStore = $systemStore; 44 | } 45 | 46 | /** 47 | * Retrieve option array with empty value 48 | * 49 | * @return string[] 50 | */ 51 | public function getAllOptions() 52 | { 53 | if ($this->_options === null) { 54 | $this->_options = $this->systemStore->getStoreValuesForForm(false, false); 55 | } 56 | return $this->_options; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Model/Source/Config/LabelType.php: -------------------------------------------------------------------------------- 1 | __('Image'), 41 | self::TEXT_TYPE => __('Text') 42 | ]; 43 | } 44 | 45 | /** 46 | * Retrieve option array with empty value 47 | * 48 | * @return string[] 49 | */ 50 | public function getAllOptions() 51 | { 52 | $result = []; 53 | 54 | foreach (self::getOptionArray() as $index => $value) { 55 | $result[] = ['value' => $index, 'label' => $value]; 56 | } 57 | 58 | return $result; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Plugin/Catalog/Block/ProductPlugin.php: -------------------------------------------------------------------------------- 1 | config = $config; 39 | } 40 | 41 | /** 42 | * Set Product 43 | * 44 | * @param $subject 45 | * @param $result 46 | * @param Image $product 47 | * @param $imageId 48 | * @param array $attribute 49 | * @return mixed 50 | */ 51 | public function afterGetImage( 52 | AbstractProduct $subject, 53 | $result, 54 | $product, 55 | $imageId, 56 | $attribute = [] 57 | ) { 58 | if ($result instanceof Image && $this->config->isEnable()) { 59 | $result->setData('product', $product); 60 | } 61 | 62 | return $result; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /view/adminhtml/templates/rule/fieldset.phtml: -------------------------------------------------------------------------------- 1 | 13 | getElement() ?> 14 | getFieldSetId() != null ? $block->getFieldSetId() : $element->getHtmlId() ?> 15 |
16 |
serialize(['class']) ?> class="fieldset"> 17 | escapeHtml($element->getLegend()) ?> 18 |
19 | getComment()) : ?> 20 |
21 |
escapeHtml($element->getComment()) ?>
22 |
23 | 24 |
25 | getChildrenHtml() ?> 26 |
27 |
28 |
29 | 42 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/Delete.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('id'); 27 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 28 | $resultRedirect = $this->resultRedirectFactory->create(); 29 | if ($id) { 30 | /** @var \Boolfly\ProductLabel\Model\Rule $model */ 31 | $model = $this->ruleFactory->create(); 32 | try { 33 | $model->load($id); 34 | $model->delete(); 35 | $this->messageManager->addSuccessMessage(__('The rule has been deleted.')); 36 | return $resultRedirect->setPath('*/*/'); 37 | } catch (\Exception $e) { 38 | $this->messageManager->addErrorMessage(__('Something went wrong while deleted the rule.')); 39 | $this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e->getMessage()); 40 | } 41 | } 42 | 43 | return $resultRedirect->setPath('*/*/'); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/NewConditionHtml.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('id'); 28 | $formName = $this->getRequest()->getParam('form_namespace'); 29 | $typeArr = explode('|', str_replace('-', '/', $this->getRequest()->getParam('type'))); 30 | $type = $typeArr[0]; 31 | 32 | $model = $this->_objectManager->create($type) 33 | ->setId($id) 34 | ->setType($type) 35 | ->setRule($this->ruleFactory->create()) 36 | ->setPrefix('conditions'); 37 | 38 | if (!empty($typeArr[1])) { 39 | $model->setAttribute($typeArr[1]); 40 | } 41 | 42 | if ($model instanceof AbstractCondition) { 43 | $model->setJsFormObject($this->getRequest()->getParam('form')); 44 | $model->setFormName($formName); 45 | $html = $model->asHtmlRecursive(); 46 | } else { 47 | $html = ''; 48 | } 49 | $this->getResponse()->setBody($html); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Model/Source/Config/Type.php: -------------------------------------------------------------------------------- 1 | __('New'), 46 | self::SALE_LABEL => __('Sale'), 47 | self::BEST_SELLER_LABEL => __('Best Seller'), 48 | self::CUSTOM_LABEL => __('Custom') 49 | ]; 50 | } 51 | 52 | /** 53 | * Retrieve option array with empty value 54 | * 55 | * @return string[] 56 | */ 57 | public function getAllOptions() 58 | { 59 | $result = []; 60 | 61 | foreach (self::getOptionArray() as $index => $value) { 62 | $result[] = ['value' => $index, 'label' => $value]; 63 | } 64 | 65 | return $result; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Model/Source/Config/Status.php: -------------------------------------------------------------------------------- 1 | __('Enabled'), self::STATUS_DISABLED => __('Disabled')]; 39 | } 40 | 41 | /** 42 | * Retrieve option array with empty value 43 | * 44 | * @return string[] 45 | */ 46 | public function getAllOptions() 47 | { 48 | $result = []; 49 | 50 | foreach (self::getOptionArray() as $index => $value) { 51 | $result[] = ['value' => $index, 'label' => $value]; 52 | } 53 | 54 | return $result; 55 | } 56 | 57 | /** 58 | * Retrieve option text by option value 59 | * 60 | * @param string $optionId 61 | * @return string 62 | */ 63 | public function getOptionText($optionId) 64 | { 65 | $options = self::getOptionArray(); 66 | 67 | return isset($options[$optionId]) ? $options[$optionId] : null; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Block/Label.php: -------------------------------------------------------------------------------- 1 | helperRule = $helperRule; 52 | } 53 | 54 | /** 55 | * Set Product 56 | * 57 | * @param $product 58 | * @return $this 59 | */ 60 | public function setProduct($product) 61 | { 62 | $this->product = $product; 63 | return $this; 64 | } 65 | 66 | /** 67 | * Get Group Rule 68 | * 69 | * @return array 70 | */ 71 | public function getGroupRule() 72 | { 73 | try { 74 | return $this->helperRule->getAppliedCategoryRule($this->product); 75 | } catch (\Exception $e) { 76 | return []; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Observer/UpdateRuleAfterProductSave.php: -------------------------------------------------------------------------------- 1 | indexerRow = $indexerRow; 47 | $this->messageManager = $messageManager; 48 | } 49 | 50 | /** 51 | * @param Observer $observer 52 | */ 53 | public function execute(Observer $observer) 54 | { 55 | try { 56 | $product = $observer->getEvent()->getData('product'); 57 | if ($product instanceof Product && $product->getId()) { 58 | $this->indexerRow->execute($product->getId()); 59 | } 60 | } catch (\Exception $e) { 61 | $this->messageManager->addWarningMessage('Something went wrong while updating product label.'); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Controller/Adminhtml/AbstractRule.php: -------------------------------------------------------------------------------- 1 | coreRegistry = $coreRegistry; 57 | $this->ruleFactory = $ruleFactory; 58 | } 59 | 60 | /** 61 | * Init action 62 | * 63 | * @return $this 64 | */ 65 | protected function initAction() 66 | { 67 | $this->_view->loadLayout(); 68 | $this->_setActiveMenu( 69 | 'Boolfly_ProductLabel::rule' 70 | )->_addBreadcrumb( 71 | __('Manage Rule'), 72 | __('Manage Rule') 73 | ); 74 | return $this; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/Edit.php: -------------------------------------------------------------------------------- 1 | getRequest()->getParam('id'); 28 | /** @var \Boolfly\ProductLabel\Model\Rule $model */ 29 | $model = $this->ruleFactory->create(); 30 | $this->coreRegistry->register('current_label_rule', $model); 31 | if ($id) { 32 | $model->load($id); 33 | if (!$model->getId()) { 34 | $this->messageManager->addErrorMessage(__('This rule no longer exists.')); 35 | $this->_redirect('*/rule/*'); 36 | return; 37 | } 38 | $model->getConditions()->setFormName('label_rule_form'); 39 | $model->getConditions()->setJsFormObject( 40 | $model->getConditionsFieldSetId($model->getConditions()->getFormName()) 41 | ); 42 | $model->getActions()->setFormName('label_rule_form'); 43 | $model->getActions()->setJsFormObject( 44 | $model->getActionsFieldSetId($model->getActions()->getFormName()) 45 | ); 46 | } 47 | $data = $this->_objectManager->get('Magento\Backend\Model\Session')->getPageData(true); 48 | if (!empty($data)) { 49 | $model->addData($data); 50 | } 51 | 52 | $this->initAction(); 53 | $this->_addBreadcrumb( 54 | $id ? __('Edit Rule') : __('New Rule'), 55 | $id ? __('Edit Rule') : __('New Rule') 56 | ); 57 | $this->_view->getPage()->getConfig()->getTitle()->prepend( 58 | $model->getId() ? $model->getTitle() : __('New Rule') 59 | ); 60 | $this->_view->renderLayout(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Plugin/Catalog/Block/Product/ImagePlugin.php: -------------------------------------------------------------------------------- 1 | layout = $layout; 46 | $this->config = $config; 47 | } 48 | 49 | /** 50 | * Add Label Html after Product Image 51 | * 52 | * @param Image $image 53 | * @param string $result 54 | * @return string 55 | */ 56 | public function afterToHtml( 57 | Image $image, 58 | $result 59 | ) { 60 | if ($image->getData('product') && $result && $this->config->isEnable()) { 61 | /** @var Label $labelBlock */ 62 | $labelBlock = $this->layout->createBlock(Label::class); 63 | $labelBlock->setProduct($image->getData('product')); 64 | $labelHtml = $labelBlock->toHtml(); 65 | if ($labelHtml) { 66 | return $this->wrapper($result, $labelHtml); 67 | } 68 | } 69 | return $result; 70 | } 71 | 72 | /** 73 | * Wrapper Html 74 | * 75 | * @param $result 76 | * @param $labelHtml 77 | * @return string 78 | */ 79 | protected function wrapper($result, $labelHtml) 80 | { 81 | return rtrim(trim($result), '') . $labelHtml . ''; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Block/Product/Label.php: -------------------------------------------------------------------------------- 1 | helperRule = $helperRule; 63 | $this->registry = $registry; 64 | $this->config = $config; 65 | } 66 | 67 | /** 68 | * @return string 69 | */ 70 | protected function _toHtml() 71 | { 72 | return $this->config->isEnable() ? parent::_toHtml() : ''; 73 | } 74 | 75 | /** 76 | * Get Product 77 | * 78 | * @return mixed 79 | */ 80 | public function getProduct() 81 | { 82 | return $this->registry->registry('current_product'); 83 | } 84 | 85 | /** 86 | * Get Group Rule 87 | * 88 | * @return array 89 | */ 90 | public function getGroupRule() 91 | { 92 | try { 93 | return $this->helperRule->getAppliedProductRule($this->getProduct()); 94 | } catch (\Exception $e) { 95 | return []; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Model/Source/Config/CustomerGroup.php: -------------------------------------------------------------------------------- 1 | moduleManager = $moduleManager; 51 | $this->groupRepository = $groupRepository; 52 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 53 | } 54 | 55 | /** 56 | * @return array 57 | * @throws \Magento\Framework\Exception\LocalizedException 58 | */ 59 | public function toOptionArray() 60 | { 61 | if (!$this->moduleManager->isEnabled('Magento_Customer')) { 62 | return []; 63 | } 64 | $customerGroups = []; 65 | $groups = $this->groupRepository->getList($this->searchCriteriaBuilder->create()); 66 | /** @var GroupInterface $group */ 67 | foreach ($groups->getItems() as $group) { 68 | $customerGroups[] = [ 69 | 'label' => $group->getCode(), 70 | 'value' => $group->getId(), 71 | ]; 72 | } 73 | 74 | return $customerGroups; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Ui/Component/Listing/Columns/EditActions.php: -------------------------------------------------------------------------------- 1 | urlBuilder = $urlBuilder; 44 | parent::__construct($context, $uiComponentFactory, $components, $data); 45 | } 46 | 47 | /** 48 | * Prepare Data Source 49 | * 50 | * @param array $dataSource 51 | * @return array 52 | */ 53 | public function prepareDataSource(array $dataSource) 54 | { 55 | if (isset($dataSource['data']['items'])) { 56 | $storeId = $this->context->getFilterParam('store_id'); 57 | $fieldId = $this->getDataByPath('config/indexField'); 58 | if ($fieldId) { 59 | $routePath = $this->getDataByPath('options/routePath') ?: '*/*/edit'; 60 | foreach ($dataSource['data']['items'] as &$item) { 61 | $item[$this->getData('name')]['edit'] = [ 62 | 'href' => $this->urlBuilder->getUrl( 63 | $routePath, 64 | ['id' => $item[$fieldId], 'store' => $storeId] 65 | ), 66 | 'label' => __('Edit'), 67 | 'hidden' => false, 68 | ]; 69 | } 70 | } 71 | } 72 | 73 | return $dataSource; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /etc/db_schema_whitelist.json: -------------------------------------------------------------------------------- 1 | { 2 | "boolfly_productlabel_rule": { 3 | "column": { 4 | "rule_id": true, 5 | "title": true, 6 | "type": true, 7 | "description": true, 8 | "priority": true, 9 | "status": true, 10 | "from_date": true, 11 | "to_date": true, 12 | "conditions_serialized": true, 13 | "display_in_cat": true, 14 | "cat_position": true, 15 | "cat_label_type": true, 16 | "cat_image": true, 17 | "cat_text": true, 18 | "css_style_cat": true, 19 | "display_in_product": true, 20 | "product_position": true, 21 | "product_label_type": true, 22 | "product_image": true, 23 | "product_text": true, 24 | "css_style_product": true, 25 | "created_at": true, 26 | "updated_at": true 27 | }, 28 | "index": { 29 | "BOOLFLY_PRODUCTLABEL_RULE_RULE_ID": true 30 | }, 31 | "constraint": { 32 | "PRIMARY": true 33 | } 34 | }, 35 | "boolfly_productlabel_store": { 36 | "column": { 37 | "rule_id": true, 38 | "store_id": true 39 | }, 40 | "index": { 41 | "BOOLFLY_PRODUCTLABEL_STORE_RULE_ID": true, 42 | "BOOLFLY_PRODUCTLABEL_STORE_STORE_ID": true 43 | }, 44 | "constraint": { 45 | "PRIMARY": true, 46 | "BOOLFLY_PRDLBL_STORE_RULE_ID_BOOLFLY_PRDLBL_RULE_RULE_ID": true, 47 | "BOOLFLY_PRODUCTLABEL_STORE_STORE_ID_STORE_STORE_ID": true 48 | } 49 | }, 50 | "boolfly_productlabel_customer_group": { 51 | "column": { 52 | "rule_id": true, 53 | "customer_group_id": true 54 | }, 55 | "constraint": { 56 | "PRIMARY": true, 57 | "BOOLFLY_PRDLBL_CSTR_GROUP_RULE_ID_BOOLFLY_PRDLBL_RULE_RULE_ID": true, 58 | "BOOLFLY_PRDLBL_CSTR_GROUP_CSTR_GROUP_ID_CSTR_GROUP_CSTR_GROUP_ID": true 59 | } 60 | }, 61 | "boolfly_productlabel_product_index_rule": { 62 | "column": { 63 | "rule_id": true, 64 | "product_id": true 65 | }, 66 | "index": { 67 | "BOOLFLY_PRODUCTLABEL_PRODUCT_INDEX_RULE_RULE_ID": true, 68 | "BOOLFLY_PRODUCTLABEL_PRODUCT_INDEX_RULE_PRODUCT_ID": true 69 | }, 70 | "constraint": { 71 | "PRIMARY": true, 72 | "BOOLFLY_PRDLBL_PRD_IDX_RULE_RULE_ID_BOOLFLY_PRDLBL_RULE_RULE_ID": true 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /Model/Rule/Condition/Combine.php: -------------------------------------------------------------------------------- 1 | productFactory = $conditionFactory; 40 | parent::__construct($context, $data); 41 | $this->setType(get_class($this)); 42 | } 43 | 44 | /** 45 | * @return array 46 | */ 47 | public function getNewChildSelectOptions() 48 | { 49 | $productAttributes = $this->productFactory->create()->loadAttributeOptions()->getAttributeOption(); 50 | $attributes = []; 51 | foreach ($productAttributes as $code => $label) { 52 | $attributes[] = [ 53 | 'value' => Product::class . '|' . $code, 54 | 'label' => $label, 55 | ]; 56 | } 57 | $conditions = parent::getNewChildSelectOptions(); 58 | $conditions = array_merge_recursive( 59 | $conditions, 60 | [ 61 | [ 62 | 'value' => get_class($this), 63 | 'label' => __('Conditions Combination'), 64 | ], 65 | ['label' => __('Product Attribute'), 'value' => $attributes] 66 | ] 67 | ); 68 | return $conditions; 69 | } 70 | 71 | /** 72 | * @param array $productCollection 73 | * @return $this 74 | */ 75 | public function collectValidatedAttributes($productCollection) 76 | { 77 | foreach ($this->getConditions() as $condition) { 78 | /** @var Product|Combine $condition */ 79 | $condition->collectValidatedAttributes($productCollection); 80 | } 81 | return $this; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /view/frontend/web/css/source/_module.less: -------------------------------------------------------------------------------- 1 | .product-label-info { 2 | position: absolute; 3 | top: 0; 4 | left: 0; 5 | z-index: 100; 6 | .product-label{ 7 | text-align: center; 8 | color: #fff; 9 | font-size: 18px; 10 | display: table; 11 | line-height: 20px; 12 | padding: 4px 6px 2px 5px; 13 | margin-bottom: 5px; 14 | box-shadow: 1px 1px 1px dimgray; 15 | img { 16 | max-height: 48px; 17 | } 18 | span { 19 | padding: 2px 4px; 20 | display: block; 21 | font-size: 1.3rem; 22 | font-weight: bold; 23 | } 24 | &.sale { 25 | background: #f71602; 26 | 27 | } 28 | &.best-seller { 29 | background: #007fd4; 30 | } 31 | &.new { 32 | background: #048500d6; 33 | } 34 | &.custom { 35 | color: #000; 36 | box-shadow: none; 37 | } 38 | } 39 | &.top-right { 40 | top: 0; 41 | right: 0; 42 | margin-top: 0 !important; 43 | left: auto !important; 44 | margin-left: 0 !important; 45 | } 46 | &.top-left { 47 | top: 0; 48 | margin-top: 0 !important; 49 | left: 0 !important; 50 | margin-left: 0 !important; 51 | right: auto; 52 | } 53 | &.bot-right { 54 | top: auto !important; 55 | margin-top: 0 !important; 56 | left: auto !important; 57 | margin-left: 0 !important; 58 | bottom: 0; 59 | right: 0; 60 | } 61 | &.bot-left { 62 | top: auto !important; 63 | margin-top: 0 !important; 64 | left: 0 !important; 65 | margin-left: 0 !important; 66 | bottom: 0; 67 | right: auto; 68 | } 69 | &.mid-left { 70 | top: 50%; 71 | left: 0; 72 | margin-left: 0 !important; 73 | right: auto; 74 | } 75 | &.mid-right { 76 | top: 50%; 77 | left: auto; 78 | margin-left: 0 !important; 79 | right: 0; 80 | } 81 | &.mid-mid { 82 | top: 50%; 83 | left: 50%; 84 | right: auto; 85 | bottom: auto; 86 | } 87 | &.top-mid { 88 | top: 0; 89 | margin-top: 0 !important; 90 | left: 50%; 91 | right: auto; 92 | bottom: auto; 93 | } 94 | &.bot-mid { 95 | top: auto; 96 | bottom: 0; 97 | margin-top: 0 !important; 98 | left: 50%; 99 | right: auto; 100 | } 101 | } 102 | .product-image-container { 103 | position: relative; 104 | } 105 | 106 | .product.media { 107 | position: relative; 108 | } 109 | 110 | .products-grid { 111 | .product-item { 112 | .product-item-info:hover { 113 | z-index: 1501; 114 | .product-label { 115 | box-shadow: none; 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Observer/ProcessingImageUpload.php: -------------------------------------------------------------------------------- 1 | imageUploader = $imageUploader; 41 | } 42 | 43 | /** 44 | * @param Observer $observer 45 | * @throws \Magento\Framework\Exception\LocalizedException 46 | */ 47 | public function execute(Observer $observer) 48 | { 49 | $rule = $observer->getEvent()->getData('label_rule'); 50 | if ($rule instanceof RuleInterface) { 51 | foreach (ImageField::getField() as $field) { 52 | $this->processFile($rule, $field); 53 | } 54 | } 55 | } 56 | 57 | /** 58 | * Process File 59 | * 60 | * @param RuleInterface|\Magento\Framework\DataObject $object 61 | * @param $key 62 | * @return $this 63 | * @throws \Magento\Framework\Exception\LocalizedException 64 | */ 65 | protected function processFile(RuleInterface $object, $key) 66 | { 67 | $files = $object->getData($key); 68 | $object->setData($key, null); 69 | if (is_array($files) && !empty($files)) { 70 | foreach ($files as $file) { 71 | if (is_array($file) && empty($file['name'])) { 72 | continue; 73 | } 74 | $name = $file['name']; 75 | // Upload New File 76 | if (isset($file['type']) && $file['tmp_name']) { 77 | $this->imageUploader->moveFileFromTmp($name); 78 | } 79 | $object->setData($key, $name); 80 | } 81 | } 82 | 83 | return $this; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /etc/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | 16 | 17 | BoolflyLabelRuleCollection 18 | 19 | 20 | 21 | 22 | 23 | boolfly_productlabel_rule 24 | Boolfly\ProductLabel\Model\ResourceModel\Rule 25 | 26 | 27 | 28 | 29 | 30 | tmp/boolfly/label 31 | boolfly/label 32 | 33 | 34 | 35 | 36 | LabelImageUploader 37 | 38 | 39 | 40 | 41 | LabelImageUploader 42 | 43 | 44 | 45 | 46 | LabelImageUploader 47 | 48 | 49 | 50 | 51 | LabelImageUploader 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/MassDelete.php: -------------------------------------------------------------------------------- 1 | collectionFactory = $collectionFactory; 57 | $this->filter = $filter; 58 | } 59 | 60 | /** 61 | * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface 62 | * @throws LocalizedException 63 | */ 64 | public function execute() 65 | { 66 | $collections = $this->filter->getCollection($this->collectionFactory->create()); 67 | $totals = 0; 68 | try { 69 | /** @var \Boolfly\ProductLabel\Model\Rule $item */ 70 | foreach ($collections as $item) { 71 | $item->delete(); 72 | $totals++; 73 | } 74 | $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been updated.', $totals)); 75 | } catch (\Exception $e) { 76 | $this->messageManager->addErrorMessage(__('Something went wrong while delete the rule(s).')); 77 | } 78 | 79 | /** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */ 80 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 81 | return $resultRedirect->setPath('*/*/'); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/MassStatus.php: -------------------------------------------------------------------------------- 1 | collectionFactory = $collectionFactory; 56 | $this->filter = $filter; 57 | } 58 | 59 | /** 60 | * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface 61 | * @throws LocalizedException 62 | */ 63 | public function execute() 64 | { 65 | $collections = $this->filter->getCollection($this->collectionFactory->create()); 66 | $status = $this->getRequest()->getParam('status'); 67 | $totals = 0; 68 | try { 69 | /** @var \Boolfly\ProductLabel\Model\Rule $item */ 70 | foreach ($collections as $item) { 71 | $item->load($item->getId()); 72 | $item->setStatus($status); 73 | $item->save(); 74 | $totals++; 75 | } 76 | $this->messageManager->addSuccessMessage(__('A total of %1 record(s) have been updated.', $totals)); 77 | } catch (\Exception $e) { 78 | $this->messageManager->addErrorMessage(__('Something went wrong while update the rule(s).')); 79 | } 80 | 81 | /** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */ 82 | $resultRedirect = $this->resultFactory->create(ResultFactory::TYPE_REDIRECT); 83 | return $resultRedirect->setPath('*/*/'); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Model/ResourceModel/Rule/Collection.php: -------------------------------------------------------------------------------- 1 | _init(Rule::class, RuleResourceModel::class); 40 | } 41 | 42 | /** 43 | * Only get enable Rule 44 | * 45 | * @return Collection 46 | */ 47 | public function addActiveStatusFilter() 48 | { 49 | return $this->addFieldToFilter('status', Status::STATUS_ENABLED); 50 | } 51 | 52 | 53 | /** 54 | * Order By Type 55 | * 56 | * @param $type 57 | * @return $this 58 | */ 59 | public function addOrderByType($type) 60 | { 61 | $field = $type == 'category' ? RuleInterface::CATEGORY_POSITION : RuleInterface::PRODUCT_POSITION; 62 | $this->addOrder($field, 'DESC'); 63 | $this->addOrder(RuleInterface::PRIORITY, 'ASC'); 64 | 65 | return $this; 66 | } 67 | 68 | /** 69 | * Add Store To Filter 70 | * 71 | * @param null $storeId 72 | * @return $this 73 | */ 74 | public function addStoreToFilter($storeId = null) 75 | { 76 | if ($storeId && is_numeric($storeId)) { 77 | $conditions = $this->getConnection()->quoteInto( 78 | 'main_table.rule_id = rule_store.rule_id AND rule_store.store_id = ?', 79 | $storeId 80 | ); 81 | $this->getSelect()->joinInner( 82 | ['rule_store' => $this->getTable('boolfly_productlabel_store')], 83 | $conditions 84 | ); 85 | } 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * Add Customer Group To Filter 92 | * 93 | * @param null $groupId 94 | * @return $this 95 | */ 96 | public function addCustomerGroupToFilter($groupId = null) 97 | { 98 | if ($groupId && is_numeric($groupId)) { 99 | $conditions = $this->getConnection()->quoteInto( 100 | 'main_table.rule_id = rule_customer.rule_id AND rule_customer.customer_group_id = ?', 101 | $groupId 102 | ); 103 | $this->getSelect()->joinInner( 104 | ['rule_customer' => $this->getTable('boolfly_productlabel_customer_group')], 105 | $conditions 106 | ); 107 | } 108 | 109 | return $this; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Model/Rule/DataProvider.php: -------------------------------------------------------------------------------- 1 | collection = $collectionFactory->create(); 73 | $this->coreRegistry = $registry; 74 | parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); 75 | $this->imageUploader = $imageUploader; 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function getData() 82 | { 83 | if (isset($this->loadedData)) { 84 | return $this->loadedData; 85 | } 86 | /** @var RuleInterface | \Boolfly\ProductLabel\Model\Rule $model */ 87 | $model = $this->coreRegistry->registry('current_label_rule'); 88 | if ($model->getId()) { 89 | $data = $model->getData(); 90 | foreach (ImageField::getField() as $field) { 91 | unset($data[$field]); 92 | $imageName = $model->getData($field); 93 | if ($imageSrc = $this->imageUploader->getImageUrl($imageName)) { 94 | try { 95 | $size = $this->imageUploader->getSize($imageName); 96 | } catch (\Exception $e) { 97 | $size = 'undefined'; 98 | } 99 | $data[$field][] = [ 100 | 'name' => $imageName, 101 | 'url' => $imageSrc, 102 | 'previewType' => 'image', 103 | 'size' => $size 104 | ]; 105 | } else { 106 | $data[$field] = []; 107 | } 108 | } 109 | $this->loadedData[$model->getId()] = $data; 110 | } else { 111 | $this->loadedData = []; 112 | } 113 | 114 | return $this->loadedData; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Controller/Adminhtml/Rule/Save.php: -------------------------------------------------------------------------------- 1 | logger = $logger; 55 | $this->backendSession = $backendSession; 56 | } 57 | 58 | /** 59 | * @return mixed 60 | * @throws LocalizedException 61 | */ 62 | public function execute() 63 | { 64 | $data = $this->getRequest()->getPostValue(); 65 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 66 | $resultRedirect = $this->resultRedirectFactory->create(); 67 | if ($data) { 68 | /** @var \Boolfly\ProductLabel\Model\Rule $model */ 69 | $model = $this->ruleFactory->create(); 70 | 71 | if (!empty($data['rule_id'])) { 72 | $model->load($data['rule_id']); 73 | if (!$model->getId()) { 74 | throw new LocalizedException(__('Wrong Label Rule ID.')); 75 | } 76 | } 77 | unset($data['rule_id']); 78 | 79 | if (isset($data['rule']['conditions'])) { 80 | $data['conditions'] = $data['rule']['conditions']; 81 | unset($data['rule']); 82 | } 83 | $model->loadPost($data); 84 | $this->_objectManager->get('Magento\Backend\Model\Session')->setPageData($model->getData()); 85 | try { 86 | $this->_eventManager->dispatch( 87 | 'controller_boolfly_label_rule_save_entity_before', 88 | ['controller' => $this, 'label_rule' => $model] 89 | ); 90 | $model->save(); 91 | $this->messageManager->addSuccessMessage(__('The rule has been saved.')); 92 | $this->backendSession->setPageData(false); 93 | if ($this->getRequest()->getParam('back')) { 94 | return $resultRedirect->setPath('*/*/edit', ['id' => $model->getId(), '_current' => true]); 95 | } 96 | return $resultRedirect->setPath('*/*/'); 97 | } catch (LocalizedException $e) { 98 | $this->logger->critical($e); 99 | $this->messageManager->addErrorMessage($e->getMessage()); 100 | } catch (\Exception $e) { 101 | echo $e->getMessage(); 102 | $this->messageManager->addErrorMessage($e, __('Something went wrong while saving the rule.')); 103 | $this->logger->critical($e); 104 | $this->backendSession->setPageData($data); 105 | return $resultRedirect->setPath('*/*/edit', ['id' => $this->getRequest()->getParam('id')]); 106 | } 107 | } 108 | 109 | return $resultRedirect->setPath('*/*/'); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Block/Adminhtml/Rule/Conditions.php: -------------------------------------------------------------------------------- 1 | coreRegistry = $registry; 77 | $this->rendererFieldset = $rendererFieldset; 78 | $this->conditions = $conditions; 79 | parent::__construct($context, $data); 80 | $this->formFactory = $formFactory; 81 | } 82 | 83 | /** 84 | * @return mixed 85 | * @throws \Magento\Framework\Exception\LocalizedException 86 | */ 87 | protected function _prepareForm() 88 | { 89 | $model = $this->coreRegistry->registry('current_label_rule'); 90 | /** @var \Magento\Framework\Data\Form $form */ 91 | $form = $this->addTabToForm($model); 92 | $this->setForm($form); 93 | 94 | return parent::_prepareForm(); 95 | } 96 | 97 | /** 98 | * @param Rule $model 99 | * @param string $fieldSetId 100 | * @return \Magento\Framework\Data\Form 101 | * @throws \Magento\Framework\Exception\LocalizedException 102 | */ 103 | protected function addTabToForm($model, $fieldSetId = 'conditions_fieldset') 104 | { 105 | /** @var \Magento\Framework\Data\Form $form */ 106 | $form = $this->formFactory->create(); 107 | $form->setHtmlIdPrefix('rule_'); 108 | $renderer = $this->rendererFieldset->setTemplate($this->rendererFieldsetTemplate) 109 | ->setNewChildUrl($this->getNewChildUrl($model)) 110 | ->setFieldSetId($model->getConditionsFieldSetId($this->formName)); 111 | 112 | $fieldset = $form->addFieldset( 113 | $fieldSetId, 114 | ['legend' => __('Conditions (don\'t add conditions if rule is applied to all products)')] 115 | )->setRenderer($renderer); 116 | 117 | $fieldset->addField( 118 | 'conditions', 119 | 'text', 120 | [ 121 | 'name' => 'conditions', 122 | 'label' => __('Conditions'), 123 | 'title' => __('Conditions'), 124 | 'required' => true, 125 | 'data-form-part' => $this->formName 126 | ] 127 | )->setRule($model)->setRenderer($this->conditions); 128 | 129 | $form->setValues($model->getData()); 130 | $this->setConditionFormName($model->getConditions(), $this->formName); 131 | return $form; 132 | } 133 | 134 | /** 135 | * @param Rule $model 136 | * @return string 137 | */ 138 | private function getNewChildUrl($model) 139 | { 140 | return $this->getUrl( 141 | '*/*/newConditionHtml', 142 | [ 143 | 'form' => $model->getConditionsFieldSetId($this->formName), 144 | 'form_namespace' => $this->formName 145 | ] 146 | ); 147 | } 148 | 149 | /** 150 | * @param AbstractCondition $conditions 151 | * @param $formName 152 | */ 153 | private function setConditionFormName(AbstractCondition $conditions, $formName) 154 | { 155 | $conditions->setFormName($formName); 156 | $conditions->setJsFormObject($formName); 157 | if ($conditions->getConditions() && is_array($conditions->getConditions())) { 158 | foreach ($conditions->getConditions() as $condition) { 159 | $this->setConditionFormName($condition, $formName); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Product Label 2 | 3 | 4 | ## Installation 5 | 6 | ##### Using Composer (we recommended) 7 | 8 | ``` 9 | composer require boolfly/module-product-label 10 | ``` 11 | 12 | ## 1. Configuration 13 | 14 | ### General Configuration 15 | 16 | Login to Magento Admin, go to **Stores > Configuration > Boolfly > Product Label** 17 | 18 | ![General Configuration](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-01.png) 19 | 20 | #### General Settings 21 | 22 | ##### Enable : 23 | 27 | 28 | ## 2. Add new rule for the product menu 29 | 30 | Login to Magento Admin, go to **Catalog > Manager Rule > Add New** 31 | 32 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-02.png) 33 | 34 | ### General 35 | 36 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-03.png) 37 | 38 | ##### Enable : 39 | 43 | 44 | ##### Title: 45 | Enter name for the product label. 46 | 47 | ##### Type: 48 | 54 | 55 | ##### Description: 56 | Enter note for the rule of product label. 57 | 58 | ##### Store View: 59 | Select store view to display the product label. 60 | 61 | ##### Customer Groups: 62 | Select customer groups to apply the rule 63 | 64 | ##### From: 65 | A beginning date applies the rule. 66 | 67 | ##### To: 68 | An ending date applies the rule. 69 | 70 | ##### Priority: 71 | Enter the priority number showing the product label (the smaller number is the higher priority) 72 | 73 | 74 | ### Conditions 75 | 76 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-04.png) 77 | 78 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-05.png) 79 | 80 | Conditions (don't add conditions if rule is applied to all products) : Select the rule to apply for all products 81 | 82 | 83 | #### Product Listing 84 | 85 | ##### Is Display: 86 | 90 | 91 | ##### Position: 92 | select position to display the product label. 93 | 94 | ##### Label Type: 95 | 99 | 100 | ##### Text: 101 | Enter text to display on the product label (only apply when selecting text for label type) 102 | 103 | ##### Image: 104 | Upload image to display on the product label (only apply when selecting image for label type). 105 | 106 | ##### Css Style Code: 107 | Style inline css for the product label. 108 | 109 | #### Product Page 110 | 111 | ##### Is Display: 112 | 116 | 117 | ##### Position: 118 | select position to display the product label. 119 | 120 | ##### Label Type: 121 | 125 | 126 | ##### Text: 127 | Enter text to display on the product label (only apply when selecting text for label type) 128 | 129 | ##### Image: 130 | Upload image to display on the product label (only apply when selecting image for label type). 131 | 132 | ##### Css Style Code: 133 | Style inline css for the product label. 134 | 135 | ## 3. How does it work? 136 | 137 | ### Product Listing 138 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-06.png) 139 | 140 | ### Product Page 141 | ![New Rule](https://github.com/boolfly/wiki/blob/master/magento/magento2/images/product-label/product-label-07.png) 142 | 143 | 144 | Contribution 145 | --- 146 | Want to contribute to this extension? The quickest way is to open a [pull request on GitHub](https://help.github.com/articles/using-pull-requests) 147 | 148 | Magento 2 Extensions 149 | --- 150 | 151 | - [Ajax Wishlist](https://github.com/boolfly/ajax-wishlist) 152 | - [Quick View](https://github.com/boolfly/quick-view) 153 | - [Banner Slider](https://github.com/boolfly/banner-slider) 154 | - [Product Label](https://github.com/boolfly/product-label) 155 | - [ZaloPay](https://github.com/boolfly/zalo-pay) 156 | - [Momo](https://github.com/boolfly/momo-wallet) 157 | - [Blog](https://github.com/boolfly/blog) 158 | - [Brand](https://github.com/boolfly/brand) 159 | - [Product Question](https://github.com/boolfly/product-question) 160 | - [Sales Sequence](https://github.com/boolfly/sales-sequence) 161 | 162 | Support 163 | --- 164 | If you encounter any problems or bugs, please open an issue on [GitHub](https://github.com/boolfly/product-label/issues). 165 | 166 | Need help settings up or want to customize this extension to meet your business needs? Please email boolfly.inc@gmail.com and if we like your idea we will add this feature for free or at a discounted rate. 167 | 168 | -------------------------------------------------------------------------------- /Model/Indexer/Full.php: -------------------------------------------------------------------------------- 1 | productCollectionFactory = $collectionFactory; 92 | $this->builder = $builder; 93 | $this->resourceConnection = $resourceConnection; 94 | $this->productVisibility = $productVisibility; 95 | $this->metadataPool = $metadataPool; 96 | } 97 | 98 | /** 99 | * Set Rule 100 | * 101 | * @param Rule $rule 102 | * @return $this 103 | */ 104 | public function setRule(Rule $rule) 105 | { 106 | $this->rule = $rule; 107 | return $this; 108 | } 109 | 110 | /** 111 | * Get Rule 112 | * 113 | * @return Rule 114 | */ 115 | public function getRule() 116 | { 117 | return $this->rule; 118 | } 119 | 120 | /** 121 | * Get all Product map with rule 122 | * 123 | * @throws \Exception 124 | */ 125 | public function execute() 126 | { 127 | if ($this->getRule() && $this->getRule()->getId()) { 128 | $this->cleanData(); 129 | $productCollection = $this->getProductCollection(); 130 | $conditions = $this->getRule()->getConditions(); 131 | $this->builder->attachConditionToCollection($productCollection, $conditions); 132 | $productCollection->setPageSize(self::PAGE_SIZE); 133 | $totalsPage = $productCollection->getLastPageNumber(); 134 | $connection = $this->resourceConnection->getConnection(); 135 | $currentPage = 1; 136 | if ($productCollection->getSize() > 0) { 137 | do { 138 | $productCollection->setCurPage($currentPage); 139 | $productCollection->load(); 140 | $importData = []; 141 | foreach ($productCollection as $product) { 142 | $importData[] = [ 143 | 'rule_id' => $this->getRule()->getId(), 144 | 'product_id' => $product->getData($this->getProductIdentifierField()) 145 | ]; 146 | } 147 | $connection->insertOnDuplicate($connection->getTableName(self::FLAT_INDEX_RULE_TABLE), $importData); 148 | $currentPage++; 149 | $productCollection->clear(); 150 | } while ($currentPage <= $totalsPage); 151 | } 152 | } 153 | } 154 | 155 | /** 156 | * @param boolean $isVisibility 157 | * @return \Magento\Catalog\Model\ResourceModel\Product\Collection 158 | * @throws \Exception 159 | */ 160 | protected function getProductCollection($isVisibility = true) 161 | { 162 | $productCollection = $this->productCollectionFactory->create(); 163 | $productCollection->addFieldToFilter('status', ProductStatus::STATUS_ENABLED); 164 | if ($isVisibility) { 165 | $productCollection->setVisibility( 166 | $this->productVisibility->getVisibleInSiteIds() 167 | )->addStoreFilter(); 168 | } 169 | $productCollection->setOrder($this->getProductIdentifierField()); 170 | 171 | return $productCollection; 172 | } 173 | 174 | /** 175 | * Clean All Old Data 176 | */ 177 | private function cleanData() 178 | { 179 | $connection = $this->resourceConnection->getConnection(); 180 | $connection->delete( 181 | $connection->getTableName(self::FLAT_INDEX_RULE_TABLE), 182 | $connection->quoteInto('rule_id = ?', $this->getRule()->getId()) 183 | ); 184 | } 185 | 186 | /** 187 | * @return MetadataPool 188 | */ 189 | protected function getMetadataPool() 190 | { 191 | return $this->metadataPool; 192 | } 193 | 194 | /** 195 | * Get product entity identifier field 196 | * 197 | * @return string 198 | * @throws \Exception 199 | */ 200 | private function getProductIdentifierField() 201 | { 202 | if ($this->productEntityIdentifierField === null) { 203 | $this->productEntityIdentifierField = $this->getMetadataPool() 204 | ->getMetadata(ProductInterface::class) 205 | ->getIdentifierField(); 206 | } 207 | return $this->productEntityIdentifierField; 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /Model/Indexer/Row.php: -------------------------------------------------------------------------------- 1 | productCollectionFactory = $collectionFactory; 99 | $this->builder = $builder; 100 | $this->resourceConnection = $resourceConnection; 101 | $this->productVisibility = $productVisibility; 102 | $this->metadataPool = $metadataPool; 103 | $this->helperRule = $helperRule; 104 | } 105 | 106 | /** 107 | * Set Rule 108 | * 109 | * @param Rule $rule 110 | * @return $this 111 | */ 112 | public function setRule(Rule $rule) 113 | { 114 | $this->rule = $rule; 115 | return $this; 116 | } 117 | 118 | /** 119 | * Get Rule 120 | * 121 | * @return Rule 122 | */ 123 | public function getRule() 124 | { 125 | return $this->rule; 126 | } 127 | 128 | /** 129 | * Set Product Id 130 | * 131 | * @param $id 132 | * @return $this 133 | */ 134 | public function setProductId($id) 135 | { 136 | $this->productId = (int)$id; 137 | return $this; 138 | } 139 | 140 | /** 141 | * Get Product Id 142 | * 143 | * @return integer 144 | */ 145 | public function getProductId() 146 | { 147 | return $this->productId; 148 | } 149 | 150 | /** 151 | * @param null $id 152 | * @return $this 153 | * @throws \Exception 154 | */ 155 | public function execute($id = null) 156 | { 157 | $this->setProductId($id); 158 | $this->cleanData(); 159 | $connection = $this->resourceConnection->getConnection(); 160 | $ruleCollection = $this->helperRule->getRuleCollection(); 161 | $dataImport = []; 162 | /** @var Rule $rule */ 163 | foreach ($ruleCollection as $rule) { 164 | $productCollection = $this->getProductCollection(); 165 | $productCollection->addFieldToFilter($this->getProductIdentifierField(), $id); 166 | $this->builder->attachConditionToCollection($productCollection, $rule->getConditions()); 167 | if ($productCollection->getSize() > 0) { 168 | $dataImport[] = [ 169 | 'rule_id' => $rule->getId(), 170 | 'product_id' => $id 171 | ]; 172 | } 173 | } 174 | if (!empty($dataImport)) { 175 | $connection->insertOnDuplicate($connection->getTableName(self::FLAT_INDEX_RULE_TABLE), $dataImport); 176 | } 177 | 178 | return $this; 179 | } 180 | 181 | /** 182 | * @param boolean $isVisibility 183 | * @return \Magento\Catalog\Model\ResourceModel\Product\Collection 184 | * @throws \Exception 185 | */ 186 | protected function getProductCollection($isVisibility = true) 187 | { 188 | $productCollection = $this->productCollectionFactory->create(); 189 | $productCollection->addFieldToFilter('status', ProductStatus::STATUS_ENABLED); 190 | if ($isVisibility) { 191 | $productCollection->addFieldToFilter('visibility', ['in' => $this->productVisibility->getVisibleInSiteIds()]); 192 | } 193 | $productCollection->setOrder($this->getProductIdentifierField()); 194 | 195 | return $productCollection; 196 | } 197 | 198 | /** 199 | * Clean All Old Data 200 | */ 201 | private function cleanData() 202 | { 203 | $connection = $this->resourceConnection->getConnection(); 204 | $connection->delete( 205 | $connection->getTableName(self::FLAT_INDEX_RULE_TABLE), 206 | $connection->quoteInto('product_id = ?', $this->getProductId()) 207 | ); 208 | } 209 | 210 | /** 211 | * @return MetadataPool 212 | */ 213 | protected function getMetadataPool() 214 | { 215 | return $this->metadataPool; 216 | } 217 | 218 | /** 219 | * Get product entity identifier field 220 | * 221 | * @return string 222 | * @throws \Exception 223 | */ 224 | private function getProductIdentifierField() 225 | { 226 | if ($this->productEntityIdentifierField === null) { 227 | $this->productEntityIdentifierField = $this->getMetadataPool() 228 | ->getMetadata(ProductInterface::class) 229 | ->getIdentifierField(); 230 | } 231 | return $this->productEntityIdentifierField; 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /etc/db_schema.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 14 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 | 49 | 51 | 53 | 54 | 55 | 56 | 57 | 62 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |
74 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 87 | 92 |
93 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 |
114 | -------------------------------------------------------------------------------- /Model/ResourceModel/Rule.php: -------------------------------------------------------------------------------- 1 | dateTime = $dateTime; 44 | } 45 | 46 | /** 47 | * Initialize resource 48 | * 49 | * @return void 50 | */ 51 | public function _construct() 52 | { 53 | $this->_init('boolfly_productlabel_rule', 'rule_id'); 54 | } 55 | 56 | /** 57 | * @param AbstractModel $object 58 | * @return mixed 59 | */ 60 | protected function _afterLoad(AbstractModel $object) 61 | { 62 | $this->getLinkData($object); 63 | return parent::_afterLoad($object); 64 | } 65 | 66 | /** 67 | * Get Link Data 68 | * 69 | * @param AbstractModel $object 70 | */ 71 | private function getLinkData(AbstractModel $object) 72 | { 73 | $this->getStoreLink($object); 74 | $this->getCustomerGroupLink($object); 75 | } 76 | 77 | /** 78 | * @param AbstractModel $object 79 | */ 80 | protected function getStoreLink($object) 81 | { 82 | $stores = $this->lookupStoreIds($object->getId()); 83 | $object->setData('store_ids', $stores); 84 | } 85 | 86 | /** 87 | * @param AbstractModel $object 88 | */ 89 | protected function getCustomerGroupLink($object) 90 | { 91 | $stores = $this->lookupCustomerGroupsIds($object->getId()); 92 | $object->setData('customer_group_ids', $stores); 93 | } 94 | 95 | /** 96 | * Get Label Store Table 97 | * 98 | * @return string 99 | */ 100 | private function getStoreTable() 101 | { 102 | return $this->getTable('boolfly_productlabel_store'); 103 | } 104 | 105 | /** 106 | * Get Customer Group Table Name 107 | * 108 | * @return string 109 | */ 110 | private function getCustomerGroupsTable() 111 | { 112 | return $this->getTable('boolfly_productlabel_customer_group'); 113 | } 114 | 115 | /** 116 | * Before save 117 | * 118 | * @param AbstractModel $object 119 | * @return mixed 120 | */ 121 | protected function _beforeSave(AbstractModel $object) 122 | { 123 | $gmtDate = $this->dateTime->gmtDate(); 124 | if ($object->isObjectNew()) { 125 | $object->setData('created_at', $gmtDate); 126 | } 127 | $object->setData('updated_at', $gmtDate); 128 | 129 | return parent::_beforeSave($object); 130 | } 131 | 132 | /** 133 | * @param AbstractModel $object 134 | * @return mixed 135 | */ 136 | protected function _afterSave(AbstractModel $object) 137 | { 138 | $this->processLinkTable($object); 139 | return parent::_afterSave($object); 140 | } 141 | 142 | /** 143 | * Process data to link table 144 | * 145 | * @param AbstractModel $object 146 | * @return $this 147 | */ 148 | private function processLinkTable(AbstractModel $object) 149 | { 150 | $this->processStoreTable($object); 151 | $this->processCustomerGroupTable($object); 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Save data to boolfly_productlabel_store table 158 | * 159 | * @param \Boolfly\ProductLabel\Model\Rule|AbstractModel $object 160 | */ 161 | private function processStoreTable(AbstractModel $object) 162 | { 163 | $oldIds = $this->lookupStoreIds($object->getId()); 164 | $newIds = (array)$object->getStoreIds(); 165 | $this->updateForeignKey( 166 | $object->getId(), 167 | $newIds, 168 | $oldIds, 169 | $this->getStoreTable(), 170 | 'store_id' 171 | ); 172 | } 173 | 174 | /** 175 | * Save data to boolfly_productlabel_store table 176 | * 177 | * @param \Boolfly\ProductLabel\Model\Rule|AbstractModel $object 178 | */ 179 | private function processCustomerGroupTable(AbstractModel $object) 180 | { 181 | $oldIds = $this->lookupCustomerGroupsIds($object->getId()); 182 | $newIds = (array)$object->getCustomerGroupIds(); 183 | $this->updateForeignKey( 184 | $object->getId(), 185 | $newIds, 186 | $oldIds, 187 | $this->getCustomerGroupsTable(), 188 | 'customer_group_id' 189 | ); 190 | } 191 | 192 | /** 193 | * Get Store ids to which specified item is assigned 194 | * 195 | * @param integer $id 196 | * @return array 197 | */ 198 | public function lookupStoreIds($id) 199 | { 200 | return $this->lookupIds( 201 | $id, 202 | $this->getStoreTable(), 203 | 'store_id' 204 | ); 205 | } 206 | 207 | /** 208 | * @param $id 209 | * @return array 210 | */ 211 | protected function lookupCustomerGroupsIds($id) 212 | { 213 | return $this->lookupIds( 214 | $id, 215 | $this->getCustomerGroupsTable(), 216 | 'customer_group_id' 217 | ); 218 | } 219 | 220 | /** 221 | * Get ids to which specified item is assigned 222 | * 223 | * @param integer $id 224 | * @param string $tableName 225 | * @param string $field 226 | * @return array 227 | */ 228 | protected function lookupIds($id, $tableName, $field) 229 | { 230 | $adapter = $this->getConnection(); 231 | 232 | $select = $adapter->select()->from( 233 | $this->getTable($tableName), 234 | $field 235 | )->where( 236 | 'rule_id = ?', 237 | (int)$id 238 | ); 239 | 240 | return $adapter->fetchCol($select); 241 | } 242 | 243 | /** 244 | * @param $ruleId 245 | * @param array $newIds 246 | * @param array $oldIds 247 | * @param $table 248 | * @param $field 249 | */ 250 | protected function updateForeignKey( 251 | $ruleId, 252 | array $newIds, 253 | array $oldIds, 254 | $table, 255 | $field 256 | ) { 257 | $insert = array_diff($newIds, $oldIds); 258 | $delete = array_diff($oldIds, $newIds); 259 | if ($delete) { 260 | $where = [ 261 | 'rule_id = ?' => (int)$ruleId, 262 | $field.' IN (?)' => $delete, 263 | ]; 264 | $this->getConnection()->delete($table, $where); 265 | } 266 | if ($insert) { 267 | $data = []; 268 | foreach ($insert as $storeId) { 269 | $data[] = [ 270 | 'rule_id' => (int)$ruleId, 271 | $field => (int)$storeId, 272 | ]; 273 | } 274 | 275 | $this->getConnection()->insertMultiple($table, $data); 276 | } 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /Api/Data/RuleInterface.php: -------------------------------------------------------------------------------- 1 | " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. -------------------------------------------------------------------------------- /Model/Rule/Condition/Product.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 78 | parent::__construct( 79 | $context, 80 | $backendData, 81 | $config, 82 | $productFactory, 83 | $productRepository, 84 | $productResource, 85 | $attrSetCollection, 86 | $localeFormat, 87 | $data 88 | ); 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | public function loadAttributeOptions() 95 | { 96 | /** @var Attribute[] $productAttributes */ 97 | $productAttributes = $this->_productResource->loadAllAttributes()->getAttributesByCode(); 98 | 99 | $attributes = []; 100 | foreach ($productAttributes as $attribute) { 101 | if (!$attribute->getFrontendLabel() || $attribute->getFrontendInput() == 'text') { 102 | continue; 103 | } 104 | $attributes[$attribute->getAttributeCode()] = $attribute->getFrontendLabel(); 105 | } 106 | 107 | $this->_addSpecialAttributes($attributes); 108 | 109 | asort($attributes); 110 | $this->setAttributeOption($attributes); 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * {@inheritdoc} 117 | */ 118 | protected function _addSpecialAttributes(array &$attributes) 119 | { 120 | parent::_addSpecialAttributes($attributes); 121 | $attributes['sku'] = __('SKU'); 122 | } 123 | 124 | /** 125 | * Retrieve value element chooser URL 126 | * 127 | * @return string 128 | */ 129 | public function getValueElementChooserUrl() 130 | { 131 | $url = false; 132 | switch ($this->getAttribute()) { 133 | case 'sku': 134 | case 'category_ids': 135 | $url = 'catalog_rule/promo_widget/chooser/attribute/' . $this->getAttribute(); 136 | if ($this->getJsFormObject()) { 137 | if ($this->getRule()->getId()) { 138 | $url .= '/form/' . $this->getRule()->getConditionsFieldSetId('boolfly_label_rule_form'); 139 | } else { 140 | $url .= '/form/' . $this->getJsFormObject(); 141 | } 142 | } 143 | break; 144 | default: 145 | break; 146 | } 147 | return $url !== false ? $this->_backendData->getUrl($url) : ''; 148 | } 149 | 150 | /** 151 | * @param $collection 152 | * @return $this 153 | * @throws \Magento\Framework\Exception\LocalizedException 154 | * @throws \Magento\Framework\Exception\NoSuchEntityException 155 | */ 156 | public function addToCollection($collection) 157 | { 158 | $attribute = $this->getAttributeObject(); 159 | 160 | if ($collection->isEnabledFlat()) { 161 | $alias = array_keys($collection->getSelect()->getPart('from'))[0]; 162 | $this->joinedAttributes[$attribute->getAttributeCode()] = $alias . '.' . $attribute->getAttributeCode(); 163 | return $this; 164 | } 165 | 166 | if ('category_ids' == $attribute->getAttributeCode() || $attribute->isStatic()) { 167 | return $this; 168 | } 169 | 170 | if ($attribute->getBackend() && $attribute->isScopeGlobal()) { 171 | $this->addGlobalAttribute($attribute, $collection); 172 | } else { 173 | $this->addNotGlobalAttribute($attribute, $collection); 174 | } 175 | 176 | $attributes = $this->getRule()->getCollectedAttributes(); 177 | $attributes[$attribute->getAttributeCode()] = true; 178 | $this->getRule()->setCollectedAttributes($attributes); 179 | 180 | return $this; 181 | } 182 | 183 | /** 184 | * @param Attribute $attribute 185 | * @param ProductCollection $collection 186 | * @return $this 187 | * @throws \Magento\Framework\Exception\NoSuchEntityException 188 | */ 189 | protected function addGlobalAttribute( 190 | Attribute $attribute, 191 | ProductCollection $collection 192 | ) { 193 | $storeId = $this->storeManager->getStore()->getId(); 194 | 195 | switch ($attribute->getBackendType()) { 196 | case 'decimal': 197 | case 'datetime': 198 | case 'int': 199 | $alias = 'at_' . $attribute->getAttributeCode(); 200 | $collection->addAttributeToSelect($attribute->getAttributeCode(), 'inner'); 201 | break; 202 | default: 203 | $alias = 'at_'. md5($this->getId()) . $attribute->getAttributeCode(); 204 | $collection->getSelect()->join( 205 | [$alias => $collection->getTable('catalog_product_index_eav')], 206 | "($alias.entity_id = e.entity_id) AND ($alias.store_id = $storeId)" . 207 | " AND ($alias.attribute_id = {$attribute->getId()})", 208 | [] 209 | ); 210 | } 211 | 212 | $this->joinedAttributes[$attribute->getAttributeCode()] = $alias . '.value'; 213 | 214 | return $this; 215 | } 216 | 217 | /** 218 | * @param Attribute $attribute 219 | * @param ProductCollection $collection 220 | * @return $this 221 | * @throws \Magento\Framework\Exception\NoSuchEntityException 222 | */ 223 | protected function addNotGlobalAttribute( 224 | Attribute $attribute, 225 | ProductCollection $collection 226 | ) { 227 | $storeId = $this->storeManager->getStore()->getId(); 228 | $values = $collection->getAllAttributeValues($attribute); 229 | $validEntities = []; 230 | if ($values) { 231 | foreach ($values as $entityId => $storeValues) { 232 | if (isset($storeValues[$storeId])) { 233 | if ($this->validateAttribute($storeValues[$storeId])) { 234 | $validEntities[] = $entityId; 235 | } 236 | } else { 237 | if ($this->validateAttribute($storeValues[Store::DEFAULT_STORE_ID])) { 238 | $validEntities[] = $entityId; 239 | } 240 | } 241 | } 242 | } 243 | $this->setOperator('()'); 244 | $this->unsetData('value_parsed'); 245 | if ($validEntities) { 246 | $this->setData('value', implode(',', $validEntities)); 247 | } else { 248 | $this->unsetData('value'); 249 | } 250 | 251 | return $this; 252 | } 253 | 254 | /** 255 | * {@inheritdoc} 256 | */ 257 | public function getMappedSqlField() 258 | { 259 | $result = ''; 260 | if ($this->getAttribute() == 'category_ids') { 261 | $result = parent::getMappedSqlField(); 262 | } elseif (isset($this->joinedAttributes[$this->getAttribute()])) { 263 | $result = $this->joinedAttributes[$this->getAttribute()]; 264 | } elseif ($this->getAttributeObject()->isStatic()) { 265 | $result = $this->getAttributeObject()->getAttributeCode(); 266 | } elseif ($this->getAttributeObject()->getIsGlobal()) { 267 | $result = parent::getMappedSqlField(); 268 | } elseif ($this->getValueParsed()) { 269 | $result = 'e.entity_id'; 270 | } 271 | 272 | return $result; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /Helper/Rule.php: -------------------------------------------------------------------------------- 1 | collectionFactory = $collectionFactory; 100 | $this->dateTime = $dateTime; 101 | $this->storeManager = $storeManager; 102 | $this->metadataPool = $metadataPool; 103 | $this->resourceConnection = $resourceConnection; 104 | $this->httpContext = $httpContext; 105 | } 106 | 107 | /** 108 | * Get Customer Group Id 109 | * 110 | * @return int 111 | */ 112 | private function getCustomerGroupId() 113 | { 114 | return (int)$this->httpContext->getValue(CustomerContext::CONTEXT_GROUP); 115 | } 116 | 117 | /** 118 | * Get Rule Collection 119 | * 120 | * @param boolean $storeFilter 121 | * @param boolean $groupFilter 122 | * @return $this|Collection 123 | * @throws \Magento\Framework\Exception\NoSuchEntityException 124 | */ 125 | public function getRuleCollection($storeFilter = false, $groupFilter = false) 126 | { 127 | if ($this->ruleCollection === null) { 128 | $dateTime = $this->dateTime->gmtDate(); 129 | $startDate = [ 130 | 'or' => [ 131 | [ 132 | 'date' => true, 133 | 'to' => $dateTime, 134 | ], 135 | ['is' => new Zend_Db_Expr('null')] 136 | ] 137 | ]; 138 | $endDate = [ 139 | 'or' => [ 140 | [ 141 | 'date' => true, 142 | 'from' => $dateTime, 143 | ], 144 | ['is' => new Zend_Db_Expr('null')] 145 | ] 146 | ]; 147 | 148 | $collection = $this->collectionFactory->create() 149 | ->addActiveStatusFilter() 150 | ->addFieldToFilter('from_date', $startDate) 151 | ->addFieldToFilter('to_date', $endDate); 152 | if ($storeFilter) { 153 | $collection->addStoreToFilter($this->storeManager->getStore()->getId()); 154 | } 155 | if ($groupFilter) { 156 | $collection->addCustomerGroupToFilter($this->getCustomerGroupId()); 157 | } 158 | 159 | $this->ruleCollection = $collection; 160 | } 161 | 162 | return $this->ruleCollection; 163 | } 164 | 165 | /** 166 | * Get Apply Category Rule 167 | * 168 | * @param Product $product 169 | * @return array 170 | * @throws \Magento\Framework\Exception\NoSuchEntityException 171 | */ 172 | public function getAppliedCategoryRule(Product $product) 173 | { 174 | return $this->getAppliedRule($product, 'cat'); 175 | } 176 | 177 | /** 178 | * Get Applied Product Rule 179 | * 180 | * @param Product $product 181 | * @return array 182 | * @throws \Magento\Framework\Exception\NoSuchEntityException 183 | */ 184 | public function getAppliedProductRule(Product $product) 185 | { 186 | return $this->getAppliedRule($product); 187 | } 188 | 189 | /** 190 | * Get Applied Rule for Product 191 | * 192 | * @param Product $product 193 | * @param $type 194 | * @return array 195 | * @throws \Magento\Framework\Exception\NoSuchEntityException 196 | */ 197 | private function getAppliedRule(Product $product, $type = 'product') 198 | { 199 | $ruleIds = $this->getRuleIdsValue($product); 200 | $result = []; 201 | if (!empty($ruleIds)) { 202 | $displayField = $type == 'product' ? RuleInterface::DISPLAY_IN_PRODUCT : RuleInterface::DISPLAY_IN_CATEGORY; 203 | $position = $type == 'product' ? RuleInterface::PRODUCT_POSITION : RuleInterface::CATEGORY_POSITION; 204 | $collection = $this->getRuleCollection(true, true); 205 | $collection->addFieldToFilter($displayField, 1); 206 | $collection->addOrderByType($type); 207 | /** @var \Boolfly\ProductLabel\Model\Rule $rule */ 208 | foreach ($collection as $rule) { 209 | if (in_array($rule->getId(), $ruleIds)) { 210 | if ($rule->getType() == Type::SALE_LABEL && !$this->isSale($product)) { 211 | continue; 212 | } 213 | $result[$rule->getData($position)][] = $rule; 214 | } 215 | } 216 | } 217 | 218 | return $result; 219 | } 220 | 221 | /** 222 | * Get All Rule Ids for Product 223 | * 224 | * @param Product $product 225 | * @return array 226 | */ 227 | public function getRuleIdsValue(Product $product) 228 | { 229 | $value = (string)$product->getData(self::ALIAS_LABEL_RULE_ID); 230 | return $value ? array_unique(explode(',', $value)) : []; 231 | } 232 | 233 | /** 234 | * Check Is Sale Product 235 | * 236 | * @param Product $product 237 | * @return mixed 238 | */ 239 | private function isSale(Product $product) 240 | { 241 | $regularPrice = $product->getPriceInfo() 242 | ->getPrice(Price\RegularPrice::PRICE_CODE) 243 | ->getAmount() 244 | ->getValue(); 245 | $finalPrice = $product->getPriceInfo() 246 | ->getPrice(Price\FinalPrice::PRICE_CODE) 247 | ->getAmount() 248 | ->getValue(); 249 | 250 | if ($regularPrice > $finalPrice) { 251 | return true; 252 | } 253 | 254 | return false; 255 | } 256 | 257 | /** 258 | * Add Rule Ids to Product Collection 259 | * 260 | * @param ProductCollection $collection 261 | * @throws \Exception 262 | */ 263 | public function addRuleIdsToCollection($collection) 264 | { 265 | if ($collection instanceof ProductCollection && !$collection->isLoaded()) { 266 | $connection = $collection->getConnection(); 267 | $col = new Zend_Db_Expr('GROUP_CONCAT(rule_id)'); 268 | $cond = $connection->quoteColumnAs('e.' . $this->getProductIdentifierField(), null) 269 | . ' = ' . $connection->quoteColumnAs('label_rule.product_id', null); 270 | $select = $connection->select() 271 | ->from($connection->getTableName(IndexerRow::FLAT_INDEX_RULE_TABLE), 272 | ['product_id', self::ALIAS_LABEL_RULE_ID => $col] 273 | )->group('product_id'); 274 | $collection->getSelect() 275 | ->joinLeft( 276 | ['label_rule' => $select], 277 | $cond, 278 | self::ALIAS_LABEL_RULE_ID 279 | ); 280 | } 281 | } 282 | 283 | /** 284 | * Add Rule Ids to Product 285 | * 286 | * @param Product $product 287 | * @throws \Exception 288 | */ 289 | public function addRuleIds(Product $product) 290 | { 291 | if ($product->getData(self::ALIAS_LABEL_RULE_ID) === null) { 292 | $productId = $product->getId(); 293 | $connection = $this->resourceConnection->getConnection(); 294 | $column = new Zend_Db_Expr('GROUP_CONCAT(rule_id)'); 295 | $select = $connection->select()->from( 296 | $connection->getTableName(IndexerRow::FLAT_INDEX_RULE_TABLE), 297 | $column 298 | )->where('product_id = ?', (int)$productId); 299 | $product->setData(self::ALIAS_LABEL_RULE_ID, $connection->fetchOne($select)); 300 | } 301 | } 302 | 303 | /** 304 | * Get Meta Data 305 | * 306 | * @return MetadataPool 307 | */ 308 | protected function getMetadataPool() 309 | { 310 | return $this->metadataPool; 311 | } 312 | 313 | /** 314 | * Get product entity identifier field 315 | * 316 | * @return string 317 | * @throws \Exception 318 | */ 319 | private function getProductIdentifierField() 320 | { 321 | if ($this->productEntityIdentifierField === null) { 322 | $this->productEntityIdentifierField = $this->getMetadataPool() 323 | ->getMetadata(ProductInterface::class) 324 | ->getIdentifierField(); 325 | } 326 | return $this->productEntityIdentifierField; 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/boolfly_label_rule_listing.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 15 | boolfly_label_rule_listing.boolfly_label_rule_listing_data_source 16 | boolfly_label_rule_listing.boolfly_label_rule_listing_data_source 17 | 18 | label_rule_columns 19 | 20 | 21 | add 22 | Add New 23 | primary 24 | */*/new 25 | 26 | 27 | 28 | 29 | 30 | Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider 31 | boolfly_label_rule_listing_data_source 32 | rule_id 33 | id 34 | 35 | 36 | 37 | 38 | rule_id 39 | 40 | 41 | 42 | 43 | 44 | 45 | Magento_Ui/js/grid/provider 46 | 47 | 48 | 49 | 50 | 51 | 52 | ui/grid/toolbar 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Magento\Store\Ui\Component\Listing\Column\Store\Options 61 | 62 | 63 | 64 | ${ $.parentName } 65 | store_id 66 | All Store Views 67 | Store View 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | boolfly_label_rule_listing.boolfly_label_rule_listing.label_rule_columns.ids 76 | Magento_Ui/js/grid/tree-massactions 77 | entity_id 78 | 79 | 80 | 81 | 82 | 83 | delete 84 | Delete 85 | 86 | 87 | Delete items 88 | Are you sure to delete selected items? 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | status 97 | Change status 98 | 99 | 100 | 101 | 102 | enable 103 | Enable 104 | 105 | 1 106 | 107 | 108 | 109 | disable 110 | Disable 111 | 112 | 2 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | boolfly_label_rule_listing.boolfly_label_rule_listing.listing_top.bookmarks 125 | current 126 | 127 | 128 | boolfly_label_rule_listing.boolfly_label_rule_listing.label_rule_columns.ids 129 | true 130 | id 131 | 132 | 133 | false 134 | 135 | 136 | 137 | 138 | boolfly_label_rule_listing.boolfly_label_rule_listing.label_rule_columns_editor 139 | startEdit 140 | 141 | ${ $.$data.rowIndex } 142 | true 143 | 144 | 145 | 146 | boolfly_label_rule_listing.boolfly_label_rule_listing.listing_top.bookmarks 147 | columns.${ $.index } 148 | current.${ $.storageConfig.root } 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | rule_id 157 | 10 158 | 159 | 160 | 161 | 162 | 163 | 164 | textRange 165 | asc 166 | ID 167 | 20 168 | 169 | 170 | 171 | 172 | 173 | 174 | text 175 | Title 176 | 30 177 | 178 | 179 | 180 | 181 | 182 | 183 | dateRange 184 | From Date 185 | 40 186 | 187 | 188 | 189 | 190 | 191 | 192 | dateRange 193 | To Date 194 | 50 195 | 196 | 197 | 198 | 199 | 200 | 201 | text 202 | Priority 203 | 70 204 | 205 | 206 | 207 | 208 | 209 | Boolfly\ProductLabel\Model\Source\Config\Status 210 | 211 | select 212 | Magento_Ui/js/grid/columns/select 213 | select 214 | Status 215 | 90 216 | 217 | 218 | 219 | 220 | 221 | 222 | text 223 | false 224 | Description 225 | 100 226 | 227 | 228 | 229 | 230 | 231 | rule_id 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /Model/Condition/Sql/Builder.php: -------------------------------------------------------------------------------- 1 | 'eq', 49 | '!=' => 'neq', 50 | '>=' => 'gteq', 51 | '>' => 'gt', 52 | '<=' => 'lteq', 53 | '<' => 'lt', 54 | '{}' => 'in', 55 | '!{}' => 'nin', 56 | '()' => 'in', 57 | '!()' => 'nin', 58 | ]; 59 | 60 | protected $stockStatusAttributeCode = 'quantity_and_stock_status'; 61 | 62 | 63 | /** 64 | * @var ExpressionFactory 65 | */ 66 | protected $expressionFactory; 67 | 68 | /** 69 | * @var EavConfig 70 | */ 71 | protected $eavConfig; 72 | 73 | /** 74 | * @var string 75 | */ 76 | protected $productEntityIdentifierField; 77 | 78 | /** 79 | * @var MetadataPool 80 | */ 81 | protected $metadataPool; 82 | 83 | /** 84 | * Builder constructor. 85 | * 86 | * @param ExpressionFactory $expressionFactory 87 | * @param ResourceConnection $resourceConnection 88 | * @param MetadataPool $metadataPool 89 | * @param EavConfig $eavConfig 90 | */ 91 | public function __construct( 92 | ExpressionFactory $expressionFactory, 93 | ResourceConnection $resourceConnection, 94 | MetadataPool $metadataPool, 95 | EavConfig $eavConfig 96 | ) { 97 | $this->expressionFactory = $expressionFactory; 98 | $this->connection = $resourceConnection->getConnection(); 99 | $this->eavConfig = $eavConfig; 100 | $this->metadataPool = $metadataPool; 101 | } 102 | 103 | /** 104 | * @param AbstractCollection $collection 105 | * @param Combine $combine 106 | * @throws \Exception 107 | */ 108 | public function attachConditionToCollection( 109 | AbstractCollection $collection, 110 | Combine $combine 111 | ) { 112 | $joinTables = $this->getCombineTablesToJoin($combine); 113 | $this->joinTablesToCollection($collection, $joinTables); 114 | $whereExpression = (string)$this->getMappedSqlCombination($combine); 115 | if (!empty($whereExpression)) { 116 | $collection->getSelect()->where($whereExpression); 117 | } 118 | } 119 | 120 | /** 121 | * Get Connection 122 | * 123 | * @return \Magento\Framework\DB\Adapter\AdapterInterface 124 | */ 125 | private function getConnection() 126 | { 127 | return $this->connection; 128 | } 129 | 130 | /** 131 | * @param Combine $combine 132 | * @return array 133 | * @throws \Exception 134 | */ 135 | protected function getCombineTablesToJoin(Combine $combine) 136 | { 137 | $joinTables = []; 138 | 139 | /** @var Product|Combine $condition */ 140 | foreach ($combine->getConditions() as $condition) { 141 | if ($condition instanceof Combine) { 142 | $joinTables[] = ['sub' => $this->getCombineTablesToJoin($condition)]; 143 | } else { 144 | $attribute = $condition->getAttributeObject(); 145 | if ($attribute->getId()) { 146 | if ($attribute->getAttributeCode() === $this->stockStatusAttributeCode) { 147 | $joinTables[] = $this->getTableJoinStockStatus(); 148 | } elseif ($attribute->getBackendType() != 'static') { 149 | $joinTables[] = $this->getTableJoin($attribute); 150 | } 151 | } 152 | } 153 | } 154 | 155 | return $joinTables; 156 | } 157 | 158 | /** 159 | * Get Info to join cataloginventory_stock_status 160 | * 161 | * @return array 162 | * @throws \Exception 163 | */ 164 | private function getTableJoinStockStatus() 165 | { 166 | $alias = 'stock_status'; 167 | $connection = $this->getConnection(); 168 | $productIdentifierField = $this->getProductIdentifierField(); 169 | $joinCondition = $connection->quoteColumnAs($alias . '.product_id', null) 170 | . ' = ' . $connection->quoteColumnAs('e.'. $productIdentifierField, null); 171 | 172 | return [ 173 | 'alias' => $alias, 174 | 'table' => 'cataloginventory_stock_status', 175 | 'column' => $alias . '.stock_status' . ' AS stock_status', 176 | 'conditions' => [ 177 | $joinCondition 178 | ] 179 | ]; 180 | } 181 | 182 | /** 183 | * @param \Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute 184 | * @return array 185 | * @throws \Exception 186 | */ 187 | protected function getTableJoin($attribute) 188 | { 189 | $connection = $this->getConnection(); 190 | $alias = $this->getAlias($attribute->getAttributeCode()); 191 | $productIdentifierField = $this->getProductIdentifierField(); 192 | $joinCondition = $connection->quoteColumnAs($alias . '.' . $productIdentifierField, null) 193 | . ' = ' . $connection->quoteColumnAs('e.'. $productIdentifierField, null); 194 | 195 | return [ 196 | 'alias' => $alias, 197 | 'table' => 'catalog_product_entity_' . $attribute->getBackendType(), 198 | 'column' => $this->checkIfExistColumn($alias) . ' AS ' . $attribute->getAttributeCode(), 199 | 'conditions' => [ 200 | $joinCondition, 201 | $connection->quoteInto($alias . '.attribute_id = ?', $attribute->getId()), 202 | $connection->quoteInto($alias . '.store_id = ?', Store::DEFAULT_STORE_ID), 203 | ] 204 | ]; 205 | } 206 | 207 | /** 208 | * Get Alias 209 | * 210 | * @param $attributeCode 211 | * @return string 212 | */ 213 | protected function getAlias($attributeCode) 214 | { 215 | return 'at_'. $attributeCode; 216 | } 217 | 218 | /** 219 | * Get Expression Column 220 | * 221 | * @param $alias 222 | * @return Expression 223 | */ 224 | protected function checkIfExistColumn($alias) 225 | { 226 | $out = 'IF(' . $alias . '.value_id > 0, '. $alias .'.value, null)'; 227 | return $this->expressionFactory->create(['expression' => $out]); 228 | } 229 | 230 | /** 231 | * Join tables from conditions combination to collection 232 | * 233 | * @param AbstractCollection $collection 234 | * @param $joinTables 235 | * @param array $joined 236 | * @throws \Zend_Db_Select_Exception 237 | */ 238 | protected function joinTablesToCollection(AbstractCollection $collection, $joinTables, $joined = []) 239 | { 240 | $joined = array_merge_recursive( 241 | array_keys($collection->getSelect()->getPart(Zend_Db_Select::FROM)), 242 | $joined 243 | ); 244 | if (is_array($joinTables)) { 245 | foreach ($joinTables as $table) { 246 | if (isset($table['sub'])) { 247 | $this->joinTablesToCollection($collection, $table['sub'], $joined); 248 | } else { 249 | if (isset($table['alias']) 250 | && !in_array($table['alias'], $joined) 251 | && !empty($table) 252 | ) { 253 | $cond = implode(' AND ', $table['conditions']); 254 | $tableName = $this->connection->getTableName($table['table']); 255 | $collection->getSelect()->joinLeft([$table['alias'] => $tableName], $cond, $table['column']); 256 | $joined[] = $table['alias']; 257 | } 258 | } 259 | } 260 | } 261 | } 262 | 263 | /** 264 | * Mapped Sql Combination 265 | * 266 | * @param Combine $combine 267 | * @param string $value 268 | * @return Expression 269 | * @throws \Exception 270 | */ 271 | protected function getMappedSqlCombination(Combine $combine, $value = '') 272 | { 273 | $out = $value ? $value : ''; 274 | $value = $combine->getValue() ? '' : ' NOT '; 275 | $getAggregator = $combine->getAggregator(); 276 | $conditions = $combine->getConditions(); 277 | /** @var AbstractCondition|Combine $condition */ 278 | foreach ($conditions as $key => $condition) { 279 | $con = $getAggregator == 'any' ? Select::SQL_OR : Select::SQL_AND; 280 | $con = isset($conditions[$key + 1]) ? $con : ''; 281 | if ($condition instanceof Combine) { 282 | $out .= $this->getMappedSqlCombination($condition, $value); 283 | } else { 284 | $out .= ' ' . $this->getMappedSqlCondition($condition, $value); 285 | } 286 | $out .= $out ? (' ' . $con) : ''; 287 | } 288 | return $this->expressionFactory->create(['expression' => $out]); 289 | } 290 | 291 | /** 292 | * Mapped Sql Condition 293 | * 294 | * @param AbstractCondition $condition 295 | * @param string $out 296 | * @return string 297 | * @throws \Exception 298 | */ 299 | protected function getMappedSqlCondition(AbstractCondition $condition, $out = '') 300 | { 301 | /** @var Product $condition */ 302 | $attribute = $condition->getAttributeObject(); 303 | if ($attribute->getId()) { 304 | $value = $condition->getValue(); 305 | $connection = $this->getConnection(); 306 | $operator = $condition->getOperator(); 307 | $alias = $this->getAlias($attribute->getAttributeCode()); 308 | $column = $this->checkIfExistColumn($alias); 309 | if ($attribute->getAttributeCode() === $this->stockStatusAttributeCode) { 310 | $column = 'stock_status.stock_status'; 311 | } 312 | $conditionOperator = $this->getConditionOperator($operator); 313 | if ($attribute->getBackendType() !== 'static' && $conditionOperator) { 314 | if ($attribute->getFrontendInput() === 'multiselect') { 315 | return $this->getMappedSqlConditionMultiselect($operator, $column, $value); 316 | } elseif (is_string($value)) { 317 | return $connection->prepareSqlCondition($column, [$conditionOperator => $value]); 318 | } 319 | } elseif ($attribute->getAttributeCode() == 'sku') { 320 | $value = strpos('in', $conditionOperator) === false ?: $condition->getValueParsed(); 321 | return $connection->prepareSqlCondition($attribute->getAttributeCode(), [$conditionOperator => $value]); 322 | } elseif ($attribute->getAttributeCode() == 'category_ids') { 323 | return $this->getMappedSqlConditionCategoryIds($operator, $condition->getValueParsed()); 324 | } 325 | } 326 | return $out; 327 | } 328 | 329 | /** 330 | * @param $operator 331 | * @return mixed|null 332 | */ 333 | private function getConditionOperator($operator) 334 | { 335 | return isset($this->conditionOperatorMaps[$operator]) ? $this->conditionOperatorMaps[$operator] : null; 336 | } 337 | 338 | /** 339 | * Mapped Sql Condition Multiselect 340 | * 341 | * @param $operator 342 | * @param $column 343 | * @param $value 344 | * @return string 345 | */ 346 | protected function getMappedSqlConditionMultiselect($operator, $column, $value) 347 | { 348 | if (is_array($value)) { 349 | $conditionOperator = strpos($operator, '!') === false ? 'finset' : 'nfinset'; 350 | $multiValue = []; 351 | foreach ($value as $val) { 352 | $multiValue[] = $this->connection->prepareSqlCondition($column, [$conditionOperator => $val]); 353 | } 354 | $cond = strpos($operator, '()') !== false ? ' OR ' : ' AND '; 355 | return implode($cond, $multiValue); 356 | } 357 | 358 | return ''; 359 | } 360 | 361 | /** 362 | * Sql Condition for Category Ids 363 | * 364 | * @param $operator 365 | * @param $valueParsed 366 | * @return mixed 367 | * @throws \Exception 368 | */ 369 | protected function getMappedSqlConditionCategoryIds($operator, $valueParsed) 370 | { 371 | if (is_array($valueParsed) && !empty($valueParsed)) { 372 | $conditionCategory = $this->connection->select() 373 | ->from( 374 | $this->connection->getTableName('catalog_category_product'), 375 | ['product_id'] 376 | )->where( 377 | 'category_id IN (?)', 378 | $valueParsed 379 | )->__toString(); 380 | if ($operator == '==') { 381 | $operator = '{}'; 382 | } 383 | if ($operator == '!=') { 384 | $operator = '!{}'; 385 | } 386 | $productIdentifierField = $this->connection->quoteColumnAs('e.' . $this->getProductIdentifierField(), null); 387 | $conditionOperator = $this->getConditionOperator($operator); 388 | $sqlCondition = $this->connection->prepareSqlCondition($productIdentifierField, [$conditionOperator => self::FAKE_VALUE]); 389 | return str_replace(self::FAKE_VALUE, $conditionCategory, $sqlCondition); 390 | } 391 | 392 | return ''; 393 | } 394 | 395 | /** 396 | * @return MetadataPool 397 | */ 398 | protected function getMetadataPool() 399 | { 400 | return $this->metadataPool; 401 | } 402 | 403 | /** 404 | * Get product entity identifier field 405 | * 406 | * @return string 407 | * @throws \Exception 408 | */ 409 | private function getProductIdentifierField() 410 | { 411 | if ($this->productEntityIdentifierField === null) { 412 | $this->productEntityIdentifierField = $this->getMetadataPool() 413 | ->getMetadata(ProductInterface::class) 414 | ->getIdentifierField(); 415 | } 416 | return $this->productEntityIdentifierField; 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /Model/Rule.php: -------------------------------------------------------------------------------- 1 | combineFactory = $combineFactory; 103 | $this->actionCollectionFactory = $actionCollectionFactory; 104 | $this->storeManager = $storeManager; 105 | $this->imageUploader = $imageUploader; 106 | parent::__construct( 107 | $context, 108 | $registry, 109 | $formFactory, 110 | $localeDate, 111 | $resource, 112 | $resourceCollection, 113 | $data 114 | ); 115 | } 116 | 117 | /** 118 | * Initialize resource model 119 | * 120 | * @return void 121 | */ 122 | public function _construct() 123 | { 124 | $this->_init(RuleResourceModel::class); 125 | } 126 | 127 | /** 128 | * Getter for rule conditions collection 129 | * 130 | * @return \Magento\Rule\Model\Condition\Combine 131 | */ 132 | public function getConditionsInstance() 133 | { 134 | return $this->combineFactory->create(); 135 | } 136 | 137 | /** 138 | * @return \Magento\Rule\Model\Action\Collection 139 | */ 140 | public function getActionsInstance() 141 | { 142 | return $this->actionCollectionFactory->create(); 143 | } 144 | 145 | /** 146 | * @param string $formName 147 | * @return string 148 | */ 149 | public function getConditionsFieldSetId($formName = '') 150 | { 151 | return $formName . 'rule_conditions_fieldset_' . $this->getId(); 152 | } 153 | 154 | /** 155 | * @param string $formName 156 | * @return string 157 | */ 158 | public function getActionsFieldSetId($formName = '') 159 | { 160 | $this->getActions(); 161 | return $formName . 'rule_actions_fieldset_' . $this->getId(); 162 | } 163 | 164 | /** 165 | * Return unique ID(s) for each object in system 166 | * 167 | * @return string[] 168 | */ 169 | public function getIdentities() 170 | { 171 | $identities = [ 172 | self::CACHE_TAG . '_' . $this->getId(), 173 | ]; 174 | 175 | if (!$this->getId() || $this->isDeleted()) { 176 | $identities[] = self::CACHE_TAG; 177 | } 178 | 179 | return array_unique($identities); 180 | } 181 | 182 | /** 183 | * Get Title 184 | * 185 | * @return string|null 186 | * @since 1.0.0 187 | */ 188 | public function getTitle() 189 | { 190 | return $this->_getData(self::TITLE); 191 | } 192 | 193 | /** 194 | * Set Title 195 | * 196 | * @param string $title 197 | * 198 | * @return $this 199 | * @since 1.0.0 200 | */ 201 | public function setTitle($title) 202 | { 203 | return $this->setData(self::TITLE, $title); 204 | } 205 | 206 | /** 207 | * Get Type 208 | * 209 | * @return string|null 210 | * @since 1.0.0 211 | */ 212 | public function getType() 213 | { 214 | return (int)$this->_getData(self::TYPE); 215 | } 216 | 217 | /** 218 | * Set Type 219 | * 220 | * @param string $type 221 | * 222 | * @return $this 223 | * @since 1.0.0 224 | */ 225 | public function setType($type) 226 | { 227 | return $this->setData(self::TYPE, $type); 228 | } 229 | 230 | /** 231 | * Get Status 232 | * 233 | * @return boolean 234 | * @since 1.0.0 235 | */ 236 | public function getStatus() 237 | { 238 | return (boolean)$this->_getData(self::STATUS); 239 | } 240 | 241 | /** 242 | * Set Status 243 | * 244 | * @param integer|boolean $status 245 | * 246 | * @return $this 247 | * @since 1.0.0 248 | */ 249 | public function setStatus($status) 250 | { 251 | return $this->setData(self::STATUS, $status); 252 | } 253 | 254 | /** 255 | * Get Priority 256 | * 257 | * @return mixed 258 | * @since 1.0.0 259 | */ 260 | public function getPriority() 261 | { 262 | return $this->_getData(self::PRIORITY); 263 | } 264 | 265 | /** 266 | * Set Priority 267 | * 268 | * @param integer $priority 269 | * @return $this 270 | */ 271 | public function setPriority($priority) 272 | { 273 | return $this->setData(self::PRIORITY, $priority); 274 | } 275 | 276 | /** 277 | * Get Conditions Serialized 278 | * 279 | * @return mixed 280 | */ 281 | public function getConditionsSerialized() 282 | { 283 | return $this->_getData(self::CONDITIONS_SERIALIZED); 284 | } 285 | 286 | /** 287 | * Set Conditions Serialized 288 | * 289 | * @param string $conditions 290 | * @return $this 291 | */ 292 | public function setConditionsSerialized($conditions) 293 | { 294 | return $this->setData(self::CONDITIONS_SERIALIZED, $conditions); 295 | } 296 | 297 | /** 298 | * Display Label in Product List, Category 299 | * 300 | * @return boolean 301 | */ 302 | public function isDisplayInCategory() 303 | { 304 | return (boolean)$this->_getData(self::DISPLAY_IN_CATEGORY); 305 | } 306 | 307 | /** 308 | * Set Display In Category 309 | * 310 | * @param boolean $isDisplay 311 | * @return $this 312 | */ 313 | public function setDisplayInCategory($isDisplay) 314 | { 315 | return $this->setData(self::DISPLAY_IN_CATEGORY, $isDisplay); 316 | } 317 | 318 | /** 319 | * Get Category Type 320 | * 321 | * @return integer 322 | */ 323 | public function getCategoryType() 324 | { 325 | return $this->_getData(self::CATEGORY_LABEL_TYPE); 326 | } 327 | 328 | /** 329 | * Set Category Type 330 | * 331 | * @param integer $type 332 | * @return $this 333 | */ 334 | public function setCategoryType($type) 335 | { 336 | return $this->setData(self::CATEGORY_LABEL_TYPE, $type); 337 | } 338 | 339 | /** 340 | * Get Category Image 341 | * 342 | * @return mixed 343 | */ 344 | public function getCategoryImage() 345 | { 346 | return $this->_getData(self::CATEGORY_IMAGE); 347 | } 348 | 349 | /** 350 | * Set Category Image 351 | * 352 | * @param string $image 353 | * @return mixed 354 | */ 355 | public function setCategoryImage($image) 356 | { 357 | return $this->setData(self::CATEGORY_LABEL_TYPE, $image); 358 | } 359 | 360 | /** 361 | * Text Label in Category 362 | * 363 | * @return string 364 | */ 365 | public function getCategoryText() 366 | { 367 | return $this->_getData(self::CAT_TEXT); 368 | } 369 | 370 | /** 371 | * Set Text label in Category 372 | * 373 | * @param string $text 374 | * @return $this 375 | */ 376 | public function setCategoryText($text) 377 | { 378 | return $this->setData(self::CAT_TEXT, $text); 379 | } 380 | 381 | /** 382 | * Get Css Style in Category 383 | * 384 | * @return string 385 | */ 386 | public function getCssStyleCategory() 387 | { 388 | return $this->_getData(self::CSS_STYLE_CATEGORY); 389 | } 390 | 391 | /** 392 | * Set Css Style in Category 393 | * 394 | * @param string $css 395 | * @return $this 396 | */ 397 | public function setCssStyleCategory($css) 398 | { 399 | return $this->setData(self::CSS_STYLE_CATEGORY, $css); 400 | } 401 | 402 | /** 403 | * Display Label in Product List, Product 404 | * 405 | * @return boolean 406 | */ 407 | public function isDisplayInProduct() 408 | { 409 | return (boolean)$this->_getData(self::DISPLAY_IN_PRODUCT); 410 | } 411 | 412 | /** 413 | * Set Display In Product 414 | * 415 | * @param boolean $isDisplay 416 | * @return $this 417 | */ 418 | public function setDisplayInProduct($isDisplay) 419 | { 420 | return $this->setData(self::DISPLAY_IN_PRODUCT, $isDisplay); 421 | } 422 | 423 | /** 424 | * Get Product Type 425 | * 426 | * @return integer 427 | */ 428 | public function getProductType() 429 | { 430 | return $this->_getData(self::PRODUCT_LABEL_TYPE); 431 | } 432 | 433 | /** 434 | * Set Product Type 435 | * 436 | * @param integer $type 437 | * @return $this 438 | */ 439 | public function setProductType($type) 440 | { 441 | return $this->setData(self::PRODUCT_LABEL_TYPE, $type); 442 | } 443 | 444 | /** 445 | * Get Product Image 446 | * 447 | * @return mixed 448 | */ 449 | public function getProductImage() 450 | { 451 | return $this->_getData(self::PRODUCT_IMAGE); 452 | } 453 | 454 | /** 455 | * Set Product Image 456 | * 457 | * @param string $image 458 | * @return mixed 459 | */ 460 | public function setProductImage($image) 461 | { 462 | return $this->setData(self::PRODUCT_IMAGE, $image); 463 | } 464 | 465 | /** 466 | * Text Label in Product 467 | * 468 | * @return string 469 | */ 470 | public function getProductText() 471 | { 472 | return $this->_getData(self::PRODUCT_TEXT); 473 | } 474 | 475 | /** 476 | * Set Text label in Product 477 | * 478 | * @param string $text 479 | * @return $this 480 | */ 481 | public function setProductText($text) 482 | { 483 | return $this->setData(self::PRODUCT_TEXT, $text); 484 | } 485 | 486 | /** 487 | * Get Css Style in Product 488 | * 489 | * @return string 490 | */ 491 | public function getCssStyleProduct() 492 | { 493 | return $this->_getData(self::CSS_STYLE_PRODUCT); 494 | } 495 | 496 | /** 497 | * Set Css Style in Product 498 | * 499 | * @param string $css 500 | * @return $this 501 | */ 502 | public function setCssStyleProduct($css) 503 | { 504 | return $this->setData(self::CSS_STYLE_PRODUCT, $css); 505 | } 506 | 507 | /** 508 | * Get Category Position 509 | * 510 | * @return string 511 | */ 512 | public function getCategoryPosition() 513 | { 514 | return $this->_getData(self::CATEGORY_POSITION); 515 | } 516 | 517 | /** 518 | * Set Category Position 519 | * 520 | * @param $pos 521 | * @return $this 522 | */ 523 | public function setCategoryPosition($pos) 524 | { 525 | return $this->setData(self::CATEGORY_POSITION, $pos); 526 | } 527 | 528 | /** 529 | * Get Product Position 530 | * 531 | * @return string 532 | */ 533 | public function getProductPosition() 534 | { 535 | return $this->_getData(self::PRODUCT_POSITION); 536 | } 537 | 538 | /** 539 | * Set Product Position 540 | * 541 | * @param $pos 542 | * @return $this 543 | */ 544 | public function setProductPosition($pos) 545 | { 546 | return $this->setData(self::PRODUCT_POSITION, $pos); 547 | } 548 | 549 | /** 550 | * @return boolean 551 | */ 552 | public function isUseImageInList() 553 | { 554 | return $this->getCategoryType() == LabelType::IMAGE_TYPE; 555 | } 556 | 557 | /** 558 | * @return boolean 559 | */ 560 | public function isUseImageInProduct() 561 | { 562 | return $this->getProductType() == LabelType::IMAGE_TYPE; 563 | } 564 | 565 | /** 566 | * Label Image in Product Listing 567 | * 568 | * @return boolean|string 569 | * @throws \Magento\Framework\Exception\NoSuchEntityException 570 | */ 571 | public function getCategoryImageUrl() 572 | { 573 | return $this->imageUploader->getImageUrl($this->getCategoryImage()); 574 | } 575 | 576 | /** 577 | * Label Image in Product Page 578 | * 579 | * @return boolean|string 580 | * @throws \Magento\Framework\Exception\NoSuchEntityException 581 | */ 582 | public function getProductImageUrl() 583 | { 584 | return $this->imageUploader->getImageUrl($this->getProductImage()); 585 | } 586 | 587 | /** 588 | * Get Additional Class 589 | * 590 | * @return string 591 | */ 592 | public function getAdditionalClass() 593 | { 594 | $type = $this->getType(); 595 | $types = Type::getOptionArray(); 596 | $additionalClass = ''; 597 | if (!empty($types[$type])) { 598 | $additionalClass = str_replace(' ', '-', strtolower($types[$type])); 599 | } 600 | 601 | return $additionalClass; 602 | } 603 | } 604 | --------------------------------------------------------------------------------