├── .gitignore
├── docs
├── assets
│ ├── popup.png
│ ├── notice.png
│ ├── cookie_policy.png
│ ├── general_config.png
│ ├── gtm_cookie_var.png
│ ├── overview_widget.png
│ ├── privacy_policy.png
│ ├── button_widget_btn.png
│ ├── button_widget_link.png
│ ├── consent_overview.png
│ ├── cookie_group_grid.png
│ ├── gtm_analytics_var.png
│ ├── button_widget_config.png
│ ├── cookie_group_create.png
│ └── gtm_analytics_trigger.png
├── Description.md
├── Installation.md
├── GTM.md
├── Content.md
└── Configuration.md
├── view
├── adminhtml
│ ├── web
│ │ ├── images
│ │ │ └── phpro-logo-menu.png
│ │ └── css
│ │ │ └── source
│ │ │ └── _module.less
│ ├── layout
│ │ ├── phpro_cookie_consent_cookiegroup_new.xml
│ │ ├── phpro_cookie_consent_cookiegroup_index.xml
│ │ └── phpro_cookie_consent_cookiegroup_edit.xml
│ └── ui_component
│ │ ├── phpro_cookie_consent_cookie_group_listing.xml
│ │ └── phpro_cookie_consent_cookie_group_form.xml
└── frontend
│ ├── templates
│ ├── widget
│ │ ├── preferences
│ │ │ └── button.phtml
│ │ └── overview.phtml
│ ├── notice.phtml
│ └── modal
│ │ └── preferences.phtml
│ ├── web
│ ├── js
│ │ ├── notice.js
│ │ ├── model
│ │ │ └── cookie.js
│ │ └── modal
│ │ │ └── preferences.js
│ └── css
│ │ └── source
│ │ └── _module.less
│ └── layout
│ └── default.xml
├── Model
├── CookieGroupAttribute.php
├── Source
│ └── Widget
│ │ └── Button.php
├── ResourceModel
│ ├── CookieGroup.php
│ ├── CookieGroup
│ │ └── Collection.php
│ ├── AbstractResource.php
│ └── AbstractCollection.php
├── CookieGroup.php
├── CookieGroupRepository.php
└── Eav
│ └── ScopeOverriddenValue.php
├── registration.php
├── etc
├── module.xml
├── adminhtml
│ ├── routes.xml
│ ├── menu.xml
│ ├── di.xml
│ └── system.xml
├── config.xml
├── acl.xml
├── widget.xml
├── di.xml
└── db_schema.xml
├── Block
├── Widget
│ ├── Preferences
│ │ └── Button.php
│ └── Overview.php
└── Adminhtml
│ └── Store
│ └── Edit
│ ├── BackButton.php
│ ├── SaveButton.php
│ ├── GenericButton.php
│ ├── SaveAndContinueButton.php
│ └── DeleteButton.php
├── CHANGELOG.md
├── Api
├── Data
│ ├── EavModelInterface.php
│ └── CookieGroupInterface.php
└── CookieGroupRepositoryInterface.php
├── grumphp.yml
├── .github
└── workflows
│ └── grumphp.yml
├── Controller
└── Adminhtml
│ └── CookieGroup
│ ├── Index.php
│ ├── NewAction.php
│ ├── Delete.php
│ ├── Edit.php
│ └── Save.php
├── LICENSE
├── README.md
├── Setup
├── Patch
│ └── Data
│ │ ├── CookieGroupAttribute.php
│ │ └── DefaultCookieData.php
└── CookieGroupSetup.php
├── composer.json
├── Config
└── CookieConsentConfig.php
├── Ui
├── Component
│ └── Listing
│ │ └── Column
│ │ └── CookieGroupActions.php
└── DataProvider
│ └── CookieGroup
│ └── Form
│ ├── DataProvider.php
│ └── Modifier
│ └── Fields.php
├── ViewModel
└── Cookie.php
└── Helper
├── AttributesHelper.php
└── UiComponentHelper.php
/.gitignore:
--------------------------------------------------------------------------------
1 | /composer.lock
2 | /vendor
3 | .idea/
--------------------------------------------------------------------------------
/docs/assets/popup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/popup.png
--------------------------------------------------------------------------------
/docs/assets/notice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/notice.png
--------------------------------------------------------------------------------
/docs/assets/cookie_policy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/cookie_policy.png
--------------------------------------------------------------------------------
/docs/assets/general_config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/general_config.png
--------------------------------------------------------------------------------
/docs/assets/gtm_cookie_var.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/gtm_cookie_var.png
--------------------------------------------------------------------------------
/docs/assets/overview_widget.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/overview_widget.png
--------------------------------------------------------------------------------
/docs/assets/privacy_policy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/privacy_policy.png
--------------------------------------------------------------------------------
/docs/assets/button_widget_btn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/button_widget_btn.png
--------------------------------------------------------------------------------
/docs/assets/button_widget_link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/button_widget_link.png
--------------------------------------------------------------------------------
/docs/assets/consent_overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/consent_overview.png
--------------------------------------------------------------------------------
/docs/assets/cookie_group_grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/cookie_group_grid.png
--------------------------------------------------------------------------------
/docs/assets/gtm_analytics_var.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/gtm_analytics_var.png
--------------------------------------------------------------------------------
/docs/assets/button_widget_config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/button_widget_config.png
--------------------------------------------------------------------------------
/docs/assets/cookie_group_create.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/cookie_group_create.png
--------------------------------------------------------------------------------
/docs/assets/gtm_analytics_trigger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/docs/assets/gtm_analytics_trigger.png
--------------------------------------------------------------------------------
/view/adminhtml/web/images/phpro-logo-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/phpro/phpro-mage2-module-cookie-consent/HEAD/view/adminhtml/web/images/phpro-logo-menu.png
--------------------------------------------------------------------------------
/Model/CookieGroupAttribute.php:
--------------------------------------------------------------------------------
1 |
2 |
{{widget type="Phpro\CookieConsent\Block\Widget\Overview"}}
' . PHP_EOL . 130 | '{{widget type="Phpro\CookieConsent\Block\Widget\Preferences\Button" preferences_button_type="0"}}
'); 131 | 132 | $this->pageRepository->save($page); 133 | } 134 | 135 | private function createDefaultBlocks(): void 136 | { 137 | $cookiePolicyBlock = $this->blockFactory->create(); 138 | $cookiePolicyBlock->setStoreId(Store::DEFAULT_STORE_ID); 139 | $cookiePolicyBlock->setIsActive(true); 140 | $cookiePolicyBlock->setTitle('Cookie Policy Content'); 141 | $cookiePolicyBlock->setIdentifier('phpro_cookie_consent_cookie_policy_content'); 142 | $cookiePolicyBlock->setContent('To make our website even better, we use functional and analytical cookies. ' . 143 | 'Information from this website and your preferences are stored in these cookies by your browser.
'); 144 | 145 | $privacyPolicyBlock = $this->blockFactory->create(); 146 | $privacyPolicyBlock->setStoreId(Store::DEFAULT_STORE_ID); 147 | $privacyPolicyBlock->setIsActive(true); 148 | $privacyPolicyBlock->setTitle('Privacy Policy Content'); 149 | $privacyPolicyBlock->setIdentifier('phpro_cookie_consent_privacy_policy_content'); 150 | $privacyPolicyBlock->setContent('Read more about the use of cookies on this website in our privacy policy.
'); 151 | 152 | $this->blockRepository->save($cookiePolicyBlock); 153 | $this->blockRepository->save($privacyPolicyBlock); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Model/Eav/ScopeOverriddenValue.php: -------------------------------------------------------------------------------- 1 | attributeRepository = $attributeRepository; 58 | $this->metadataPool = $metadataPool; 59 | $this->searchCriteriaBuilder = $searchCriteriaBuilder; 60 | $this->filterBuilder = $filterBuilder; 61 | $this->resourceConnection = $resourceConnection; 62 | } 63 | 64 | /** 65 | * Whether attribute value is overridden in specific store 66 | * 67 | * @param string $entityType 68 | * @param \Magento\Catalog\Model\AbstractModel $entity 69 | * @param string $attributeCode 70 | * @param int|string $storeId 71 | * 72 | * @throws \Magento\Framework\Exception\LocalizedException 73 | * 74 | * @return bool 75 | */ 76 | public function containsValue($entityType, $entity, $attributeCode, $storeId) 77 | { 78 | if ((int) $storeId === Store::DEFAULT_STORE_ID) { 79 | return false; 80 | } 81 | if ($this->attributesValues === null) { 82 | $this->initAttributeValues($entityType, $entity, (int) $storeId); 83 | } 84 | 85 | return isset($this->attributesValues[$storeId]) 86 | && array_key_exists($attributeCode, $this->attributesValues[$storeId]); 87 | } 88 | 89 | /** 90 | * Get attribute default values 91 | * 92 | * @param string $entityType 93 | * @param \Magento\Catalog\Model\AbstractModel $entity 94 | * 95 | * @throws \Magento\Framework\Exception\LocalizedException 96 | * 97 | * @return array 98 | */ 99 | public function getDefaultValues($entityType, $entity) 100 | { 101 | if ($this->attributesValues === null) { 102 | $this->initAttributeValues($entityType, $entity, (int) $entity->getStoreId()); 103 | } 104 | 105 | return isset($this->attributesValues[Store::DEFAULT_STORE_ID]) 106 | ? $this->attributesValues[Store::DEFAULT_STORE_ID] 107 | : []; 108 | } 109 | 110 | /** 111 | * @param string $entityType 112 | * @param \Magento\Catalog\Model\AbstractModel $entity 113 | * @param int $storeId 114 | * 115 | * @throws \Magento\Framework\Exception\LocalizedException 116 | * 117 | * @return void 118 | */ 119 | private function initAttributeValues($entityType, $entity, $storeId) 120 | { 121 | $metadata = $this->metadataPool->getMetadata($entityType); 122 | /** @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute $attribute */ 123 | $attributeTables = []; 124 | if ($metadata->getEavEntityType()) { 125 | foreach ($this->getAttributes($entityType) as $attribute) { 126 | if (!$attribute->isStatic()) { 127 | $attributeTables[$attribute->getBackend()->getTable()][] = $attribute->getAttributeId(); 128 | } 129 | } 130 | $storeIds = [Store::DEFAULT_STORE_ID]; 131 | if ($storeId !== Store::DEFAULT_STORE_ID) { 132 | $storeIds[] = $storeId; 133 | } 134 | $selects = []; 135 | foreach ($attributeTables as $attributeTable => $attributeCodes) { 136 | $select = $metadata->getEntityConnection()->select() 137 | ->from(['t' => $attributeTable], ['value' => 't.value', 'store_id' => 't.store_id']) 138 | ->join( 139 | ['a' => $this->resourceConnection->getTableName('eav_attribute')], 140 | 'a.attribute_id = t.attribute_id', 141 | ['attribute_code' => 'a.attribute_code'] 142 | ) 143 | ->where($metadata->getLinkField() . ' = ?', $entity->getData($metadata->getLinkField())) 144 | ->where('t.attribute_id IN (?)', $attributeCodes) 145 | ->where('t.store_id IN (?)', $storeIds); 146 | $selects[] = $select; 147 | } 148 | 149 | $unionSelect = new \Magento\Framework\DB\Sql\UnionExpression( 150 | $selects, 151 | \Magento\Framework\DB\Select::SQL_UNION_ALL 152 | ); 153 | $attributes = $metadata->getEntityConnection()->fetchAll((string) $unionSelect); 154 | foreach ($attributes as $attribute) { 155 | $this->attributesValues[$attribute['store_id']][$attribute['attribute_code']] = $attribute['value']; 156 | } 157 | } 158 | } 159 | 160 | /** 161 | * @param string $entityType 162 | * 163 | * @throws \Exception 164 | * 165 | * @return \Magento\Eav\Api\Data\AttributeInterface[] 166 | */ 167 | private function getAttributes($entityType) 168 | { 169 | $metadata = $this->metadataPool->getMetadata($entityType); 170 | $searchResult = $this->attributeRepository->getList( 171 | $metadata->getEavEntityType(), 172 | $this->searchCriteriaBuilder->addFilters( 173 | [ 174 | $this->filterBuilder 175 | ->setField('backend_type') 176 | ->setConditionType('neq') 177 | ->setValue('static') 178 | ->create(), 179 | ] 180 | )->create() 181 | ); 182 | 183 | return $searchResult->getItems(); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /view/frontend/web/css/source/_module.less: -------------------------------------------------------------------------------- 1 | // 2 | // Common 3 | // _____________________________________________ 4 | 5 | & when (@media-common = true) { 6 | // 7 | // Notice bar 8 | // --------------------------------------------- 9 | .phpro-cookie-notice { 10 | width: 100vw; 11 | padding: 30px; 12 | background: @color-gray_light; 13 | position: fixed; 14 | bottom: 0; 15 | left: 0; 16 | right: 0; 17 | z-index: 900; 18 | 19 | .notice-wrapper { 20 | display: flex; 21 | flex-direction: column; 22 | max-width: @layout__max-width; 23 | margin: auto; 24 | justify-content: space-around; 25 | align-items: center; 26 | 27 | .notice__description { 28 | span { 29 | display: block; 30 | } 31 | } 32 | } 33 | } 34 | 35 | // 36 | // Preferences popup 37 | // --------------------------------------------- 38 | .modals-wrapper { 39 | .modal-popup.cookie-consent-newsletter-modal { 40 | .modal-inner-wrap { 41 | background-color: @color-gray_light; 42 | 43 | .modal-header { 44 | height: 0; 45 | padding: 0; 46 | 47 | .action-close:before { 48 | color: @color-black; 49 | } 50 | } 51 | 52 | .modal-content { 53 | padding-left: 0; 54 | padding-right: 0; 55 | } 56 | 57 | .phpro-cookie-consent-modal { 58 | display: flex; 59 | flex-direction: column; 60 | 61 | .consent-tabs { 62 | display: inline-block; 63 | vertical-align: top; 64 | width: 100%; 65 | 66 | .consent-tab { 67 | background-color: @color-gray_light; 68 | width: 100%; 69 | cursor: pointer; 70 | padding: 5px 5px 5px 20px; 71 | box-shadow: 0 5px 10px 0 rgba(0,0,0,.1); 72 | position: relative; 73 | z-index: 10; 74 | 75 | &.active { 76 | background-color: @theme__color__primary; 77 | } 78 | 79 | span { 80 | font-weight: 700; 81 | } 82 | } 83 | 84 | &-content { 85 | display: inline-block; 86 | vertical-align: top; 87 | background-color: @color-white; 88 | padding: 20px 20px 0; 89 | 90 | .consent-tab-content { 91 | position: relative; 92 | 93 | p.title { 94 | margin-bottom: 20px; 95 | font-size: @font-size__l; 96 | } 97 | 98 | .cookie-toggle-wrapper { 99 | position: absolute; 100 | right: 0; 101 | top: 0; 102 | 103 | .cookie-toggle { 104 | position: relative; 105 | display: inline-block; 106 | width: 60px; 107 | height: 34px; 108 | 109 | input { 110 | display: none; 111 | 112 | &:checked + .cookie-toggle-slider { 113 | background-color: @theme__color__primary; 114 | } 115 | 116 | &:focus + .cookie-toggle-slider { 117 | box-shadow: 0 0 1px @theme__color__primary; 118 | } 119 | 120 | &:checked + .cookie-toggle-slider:before { 121 | -webkit-transform: translateX(26px); 122 | -ms-transform: translateX(26px); 123 | transform: translateX(26px); 124 | } 125 | } 126 | 127 | .cookie-toggle-slider { 128 | position: absolute; 129 | cursor: pointer; 130 | top: 0; 131 | left: 0; 132 | right: 0; 133 | bottom: 0; 134 | -webkit-transition: .4s; 135 | transition: .4s; 136 | border-radius: 34px; 137 | background-color: @color-very-dark-gray; 138 | 139 | &:before { 140 | position: absolute; 141 | content: ""; 142 | height: 26px; 143 | width: 26px; 144 | left: 4px; 145 | bottom: 4px; 146 | background-color: white; 147 | -webkit-transition: .4s; 148 | transition: .4s; 149 | border-radius: 50%; 150 | } 151 | 152 | &.disabled { 153 | opacity: 0.5; 154 | } 155 | } 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | .modal-footer { 164 | text-align: right; 165 | background-color: @color-white; 166 | } 167 | } 168 | } 169 | } 170 | 171 | // 172 | // Cookie overview widget 173 | // --------------------------------------------- 174 | .cookie-consent-overview { 175 | p.title { 176 | margin-bottom: 20px; 177 | } 178 | 179 | .cookie-group-description { 180 | margin-bottom: 30px; 181 | } 182 | } 183 | 184 | // 185 | // Cookie preferences button widget 186 | // --------------------------------------------- 187 | .btn-cookie-preferences-show { 188 | cursor: pointer; 189 | } 190 | } 191 | 192 | // 193 | // Desktop 194 | // _____________________________________________ 195 | 196 | .media-width(@extremum, @break) when (@extremum = 'min') and (@break = @screen__m) { 197 | // 198 | // Notice bar 199 | // --------------------------------------------- 200 | .phpro-cookie-notice { 201 | .notice-wrapper { 202 | flex-direction: row; 203 | } 204 | } 205 | 206 | // 207 | // Preferences popup 208 | // --------------------------------------------- 209 | .modals-wrapper { 210 | .modal-popup.cookie-consent-newsletter-modal { 211 | .modal-inner-wrap { 212 | background-color: @color-gray_light; 213 | 214 | .modal-content { 215 | padding-left: 0; 216 | } 217 | 218 | .phpro-cookie-consent-modal { 219 | flex-direction: row; 220 | 221 | .consent-tabs { 222 | width: 20%; 223 | padding-left: 3%; 224 | background-color: @color-white; 225 | padding-top: 30px; 226 | 227 | .consent-tab { 228 | width: 80%; 229 | border: 2px solid @theme__color__primary; 230 | border-radius: 3px; 231 | padding: 5px; 232 | margin-bottom: 20px; 233 | background-color: @color-white; 234 | box-shadow: none; 235 | } 236 | 237 | &-content { 238 | background-color: @color-gray_light; 239 | width: 65%; 240 | padding-top: 30px; 241 | padding-left: 30px; 242 | padding-bottom: 50px; 243 | } 244 | } 245 | } 246 | 247 | .modal-footer { 248 | height: 0; 249 | padding: 0; 250 | text-align: right; 251 | margin-right: 20px; 252 | 253 | .consent-btn { 254 | margin: -100px 0 0 0; 255 | } 256 | } 257 | } 258 | } 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /view/adminhtml/ui_component/phpro_cookie_consent_cookie_group_form.xml: -------------------------------------------------------------------------------- 1 | 2 | 151 | -------------------------------------------------------------------------------- /Model/ResourceModel/AbstractResource.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 34 | $this->cookieGroupFactory = $cookieGroupFactory; 35 | } 36 | 37 | public function getDefaultStoreId() 38 | { 39 | return Store::DEFAULT_STORE_ID; 40 | } 41 | 42 | protected function _getLoadAttributesSelect($object, $table) 43 | { 44 | if ($this->storeManager->hasSingleStore()) { 45 | $storeId = (int) $this->storeManager->getStore(true)->getId(); 46 | } else { 47 | $storeId = (int) $object->getStoreId(); 48 | } 49 | 50 | $setId = $object->getDefaultAttributeSetId(); 51 | $storeIds = [$this->getDefaultStoreId()]; 52 | if ($storeId !== $this->getDefaultStoreId()) { 53 | $storeIds[] = $storeId; 54 | } 55 | 56 | $select = $this->getConnection() 57 | ->select() 58 | ->from(['attr_table' => $table], []) 59 | ->where("attr_table.{$this->getLinkField()} = ?", $object->getData($this->getLinkField())) 60 | ->where('attr_table.store_id IN (?)', $storeIds); 61 | 62 | if ($setId) { 63 | $select->join( 64 | ['set_table' => $this->getTable('eav_entity_attribute')], 65 | $this->getConnection()->quoteInto( 66 | 'attr_table.attribute_id = set_table.attribute_id' . ' AND set_table.attribute_set_id = ?', 67 | $setId 68 | ), 69 | [] 70 | ); 71 | } 72 | 73 | return $select; 74 | } 75 | 76 | protected function _prepareLoadSelect(array $selects) 77 | { 78 | $select = parent::_prepareLoadSelect($selects); 79 | $select->order('store_id'); 80 | 81 | return $select; 82 | } 83 | 84 | protected function _saveAttributeValue($object, $attribute, $value) 85 | { 86 | $connection = $this->getConnection(); 87 | $hasSingleStore = $this->storeManager->hasSingleStore(); 88 | $storeId = $hasSingleStore 89 | ? $this->getDefaultStoreId() 90 | : (int) $this->storeManager->getStore($object->getStoreId())->getId(); 91 | $table = $attribute->getBackend()->getTable(); 92 | 93 | $entityIdField = $this->getLinkField(); 94 | $conditions = [ 95 | 'attribute_id = ?' => $attribute->getAttributeId(), 96 | "{$entityIdField} = ?" => $object->getData($entityIdField), 97 | 'store_id <> ?' => $storeId, 98 | ]; 99 | if ($hasSingleStore 100 | && !$object->isObjectNew() 101 | && $this->isAttributePresentForNonDefaultStore($attribute, $conditions) 102 | ) { 103 | $connection->delete( 104 | $table, 105 | $conditions 106 | ); 107 | } 108 | 109 | $data = new DataObject( 110 | [ 111 | 'attribute_id' => $attribute->getAttributeId(), 112 | 'store_id' => $storeId, 113 | $entityIdField => $object->getData($entityIdField), 114 | 'value' => $this->_prepareValueForSave($value, $attribute), 115 | ] 116 | ); 117 | $bind = $this->_prepareDataForTable($data, $table); 118 | 119 | $this->_attributeValuesToSave[$table][] = $bind; 120 | 121 | return $this; 122 | } 123 | 124 | protected function _insertAttribute($object, $attribute, $value) 125 | { 126 | $storeId = (int) $this->storeManager->getStore($object->getStoreId())->getId(); 127 | if ($this->getDefaultStoreId() !== $storeId) { 128 | $table = $attribute->getBackend()->getTable(); 129 | 130 | $select = $this->getConnection()->select() 131 | ->from($table) 132 | ->where('attribute_id = ?', $attribute->getAttributeId()) 133 | ->where('store_id = ?', $this->getDefaultStoreId()) 134 | ->where($this->getLinkField() . ' = ?', $object->getData($this->getLinkField())); 135 | $row = $this->getConnection()->fetchOne($select); 136 | 137 | if (!$row) { 138 | $data = new DataObject( 139 | [ 140 | 'attribute_id' => $attribute->getAttributeId(), 141 | 'store_id' => $this->getDefaultStoreId(), 142 | $this->getLinkField() => $object->getData($this->getLinkField()), 143 | 'value' => $this->_prepareValueForSave($value, $attribute), 144 | ] 145 | ); 146 | $bind = $this->_prepareDataForTable($data, $table); 147 | $this->getConnection()->insertOnDuplicate($table, $bind, ['value']); 148 | } 149 | } 150 | 151 | return $this->_saveAttributeValue($object, $attribute, $value); 152 | } 153 | 154 | protected function _updateAttribute($object, $attribute, $valueId, $value) 155 | { 156 | return $this->_saveAttributeValue($object, $attribute, $value); 157 | } 158 | 159 | protected function _updateAttributeForStore($object, $attribute, $value, $storeId) 160 | { 161 | $connection = $this->getConnection(); 162 | $table = $attribute->getBackend()->getTable(); 163 | $entityIdField = $this->getLinkField(); 164 | $select = $connection->select() 165 | ->from($table, 'value_id') 166 | ->where("$entityIdField = :entity_field_id") 167 | ->where('store_id = :store_id') 168 | ->where('attribute_id = :attribute_id'); 169 | $bind = [ 170 | 'entity_field_id' => $object->getId(), 171 | 'store_id' => $storeId, 172 | 'attribute_id' => $attribute->getId(), 173 | ]; 174 | $valueId = $connection->fetchOne($select, $bind); 175 | /* 176 | * When value for store exist 177 | */ 178 | if ($valueId) { 179 | $bind = ['value' => $this->_prepareValueForSave($value, $attribute)]; 180 | $where = ['value_id = ?' => (int) $valueId]; 181 | 182 | $connection->update($table, $bind, $where); 183 | } else { 184 | $bind = [ 185 | $entityIdField => (int) $object->getId(), 186 | 'attribute_id' => (int) $attribute->getId(), 187 | 'value' => $this->_prepareValueForSave($value, $attribute), 188 | 'store_id' => (int) $storeId, 189 | ]; 190 | 191 | $connection->insert($table, $bind); 192 | } 193 | 194 | return $this; 195 | } 196 | 197 | private function isAttributePresentForNonDefaultStore($attribute, $conditions) 198 | { 199 | $connection = $this->getConnection(); 200 | $select = $connection->select()->from($attribute->getBackend()->getTable()); 201 | foreach ($conditions as $condition => $conditionValue) { 202 | $select->where($condition, $conditionValue); 203 | } 204 | $select->limit(1); 205 | 206 | return !empty($connection->fetchRow($select)); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /Model/ResourceModel/AbstractCollection.php: -------------------------------------------------------------------------------- 1 | storeManager = $storeManager; 46 | parent::__construct( 47 | $entityFactory, 48 | $logger, 49 | $fetchStrategy, 50 | $eventManager, 51 | $eavConfig, 52 | $resource, 53 | $eavEntityFactory, 54 | $resourceHelper, 55 | $universalFactory, 56 | $connection 57 | ); 58 | } 59 | 60 | public function setStore($store) 61 | { 62 | $this->setStoreId($this->storeManager->getStore($store)->getId()); 63 | 64 | return $this; 65 | } 66 | 67 | public function setStoreId($storeId) 68 | { 69 | if ($storeId instanceof StoreInterface) { 70 | $storeId = $storeId->getId(); 71 | } 72 | $this->storeId = (int) $storeId; 73 | 74 | return $this; 75 | } 76 | 77 | public function getStoreId() 78 | { 79 | if ($this->storeId === null) { 80 | $this->setStoreId($this->storeManager->getStore()->getId()); 81 | } 82 | 83 | return $this->storeId; 84 | } 85 | 86 | public function getDefaultStoreId() 87 | { 88 | return Store::DEFAULT_STORE_ID; 89 | } 90 | 91 | protected function getEntityPkName(AbstractEntity $entity) 92 | { 93 | return $entity->getLinkField(); 94 | } 95 | 96 | protected function _getLoadAttributesSelect($table, $attributeIds = []) 97 | { 98 | if (empty($attributeIds)) { 99 | $attributeIds = $this->_selectAttributes; 100 | } 101 | $storeId = $this->getStoreId(); 102 | $connection = $this->getConnection(); 103 | 104 | $entityTable = $this->getEntity()->getEntityTable(); 105 | $indexList = $connection->getIndexList($entityTable); 106 | $entityIdField = $indexList[$connection->getPrimaryKeyName($entityTable)]['COLUMNS_LIST'][0]; 107 | 108 | if ($storeId) { 109 | $joinCondition = [ 110 | 't_s.attribute_id = t_d.attribute_id', 111 | "t_s.{$entityIdField} = t_d.{$entityIdField}", 112 | $connection->quoteInto('t_s.store_id = ?', $storeId), 113 | ]; 114 | 115 | $select = $connection->select()->from( 116 | ['t_d' => $table], 117 | ['attribute_id'] 118 | )->join( 119 | ['e' => $entityTable], 120 | "e.{$entityIdField} = t_d.{$entityIdField}", 121 | ['e.entity_id'] 122 | )->where( 123 | 'e.entity_id IN (?)', 124 | array_keys($this->_itemsById) 125 | )->where( 126 | 't_d.attribute_id IN (?)', 127 | $attributeIds 128 | )->joinLeft( 129 | ['t_s' => $table], 130 | implode(' AND ', $joinCondition), 131 | [] 132 | )->where( 133 | 't_d.store_id = ?', 134 | $connection->getIfNullSql('t_s.store_id', Store::DEFAULT_STORE_ID) 135 | ); 136 | } else { 137 | $select = $connection->select()->from( 138 | ['t_d' => $table], 139 | ['attribute_id'] 140 | )->join( 141 | ['e' => $entityTable], 142 | "e.{$entityIdField} = t_d.{$entityIdField}", 143 | ['e.entity_id'] 144 | )->where( 145 | 'e.entity_id IN (?)', 146 | array_keys($this->_itemsById) 147 | )->where( 148 | 'attribute_id IN (?)', 149 | $attributeIds 150 | )->where( 151 | 'store_id = ?', 152 | $this->getDefaultStoreId() 153 | ); 154 | } 155 | 156 | return $select; 157 | } 158 | 159 | protected function _addLoadAttributesSelectValues($select, $table, $type) 160 | { 161 | $storeId = $this->getStoreId(); 162 | if ($storeId) { 163 | $connection = $this->getConnection(); 164 | $valueExpr = $connection->getCheckSql('t_s.value_id IS NULL', 't_d.value', 't_s.value'); 165 | 166 | $select->columns( 167 | ['default_value' => 't_d.value', 'store_value' => 't_s.value', 'value' => $valueExpr] 168 | ); 169 | } else { 170 | $select = parent::_addLoadAttributesSelectValues($select, $table, $type); 171 | } 172 | 173 | return $select; 174 | } 175 | 176 | protected function _joinAttributeToSelect($method, $attribute, $tableAlias, $condition, $fieldCode, $fieldAlias) 177 | { 178 | if (isset($this->_joinAttributes[$fieldCode]['store_id'])) { 179 | $storeId = $this->_joinAttributes[$fieldCode]['store_id']; 180 | } else { 181 | $storeId = $this->getStoreId(); 182 | } 183 | 184 | $connection = $this->getConnection(); 185 | 186 | if ($storeId !== $this->getDefaultStoreId()) { 187 | $defCondition = '(' . implode(') AND (', $condition) . ')'; 188 | $defAlias = $tableAlias . '_default'; 189 | $defAlias = $this->getConnection()->getTableName($defAlias); 190 | $defFieldAlias = str_replace($tableAlias, $defAlias, $fieldAlias); 191 | $tableAlias = $this->getConnection()->getTableName($tableAlias); 192 | 193 | $defCondition = str_replace($tableAlias, $defAlias, $defCondition); 194 | $defCondition .= $connection->quoteInto( 195 | ' AND ' . $connection->quoteColumnAs("{$defAlias}.store_id", null) . ' = ?', 196 | $this->getDefaultStoreId() 197 | ); 198 | 199 | $this->getSelect()->{$method}( 200 | [$defAlias => $attribute->getBackend()->getTable()], 201 | $defCondition, 202 | [] 203 | ); 204 | 205 | $method = 'joinLeft'; 206 | $fieldAlias = $this->getConnection()->getCheckSql( 207 | "{$tableAlias}.value_id > 0", 208 | $fieldAlias, 209 | $defFieldAlias 210 | ); 211 | $this->_joinAttributes[$fieldCode]['condition_alias'] = $fieldAlias; 212 | $this->_joinAttributes[$fieldCode]['attribute'] = $attribute; 213 | } else { 214 | $storeId = $this->getDefaultStoreId(); 215 | } 216 | $condition[] = $connection->quoteInto( 217 | $connection->quoteColumnAs("{$tableAlias}.store_id", null) . ' = ?', 218 | $storeId 219 | ); 220 | 221 | return parent::_joinAttributeToSelect($method, $attribute, $tableAlias, $condition, $fieldCode, $fieldAlias); 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /etc/db_schema.xml: -------------------------------------------------------------------------------- 1 | 2 |