Skip to content

Commit 73cb9bb

Browse files
committed
Merge branch 'fix_virtual-categories-rules' into 'release_1.4'
Fix virtual categories rules See merge request !74
2 parents 7cf01ea + 9a314f7 commit 73cb9bb

File tree

7 files changed

+125
-93
lines changed

7 files changed

+125
-93
lines changed

src/app/code/community/Smile/VirtualAttributes/Model/Rule.php

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -67,55 +67,6 @@ public function addUsedAttributeIds($attributeIds)
6767
return $this;
6868
}
6969

70-
/**
71-
* Store attribute query into the local cache.
72-
*
73-
* @param int $cacheId Cache key for a given pair of attribute and option.
74-
* @param string $data Data to cache [query, used_attributes].
75-
*
76-
* @return Smile_VirtualAttributes_Model_Rule
77-
*/
78-
public function cacheQuery($cacheId, $data)
79-
{
80-
$cacheInstance = Mage::getSingleton('smile_virtualattributes/rule');
81-
$cacheInstance->_queryCache[$cacheId] = $data;
82-
83-
$cacheTags = array(Mage_Eav_Model_Entity_Attribute::CACHE_TAG);
84-
85-
foreach ($data[1] as $usedAttributeId) {
86-
$cacheTags[] = Mage_Eav_Model_Attribute::CACHE_TAG . '_' . $usedAttributeId;
87-
}
88-
89-
$cacheId = self::CACHE_KEY_PREFIX . '_' .$cacheId;
90-
91-
Mage::app()->saveCache(serialize($data), $cacheId, $cacheTags, Mage_Core_Model_Cache::DEFAULT_LIFETIME);
92-
93-
return $this;
94-
}
95-
96-
/**
97-
* Local caching of queries. Used when a category query is retrieved several times during the same request.
98-
*
99-
* @param int $cacheId Cache key for a given pair of attribute and option.
100-
*
101-
* @return NULL|string
102-
*/
103-
public function getQueryFromCache($cacheId)
104-
{
105-
$cacheInstance = Mage::getSingleton('smile_virtualattributes/rule');
106-
$data = false;
107-
108-
if (isset($cacheInstance->_queryCache[$cacheId])) {
109-
$data = $cacheInstance->_queryCache[$cacheId];
110-
}
111-
112-
if ($data === false && $cacheData = Mage::app()->loadCache(self::CACHE_KEY_PREFIX . '_' . $cacheId)) {
113-
$data = unserialize($cacheData);
114-
}
115-
116-
return $data;
117-
}
118-
11970
/**
12071
* Retrieve an array of queries for each attribute option
12172
*

src/app/code/community/Smile/VirtualCategories/Helper/Data.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ public function getVirtualRootCategory($category)
9191
}
9292
if ($categoryId) {
9393
$rootCategory = Mage::getModel("catalog/category")->load($categoryId);
94+
if (!$rootCategory->getId()) {
95+
$rootCategory = null;
96+
}
9497
}
9598
}
9699
$this->_virtualCategoriesRootCache[$cacheKey] = $rootCategory;

src/app/code/community/Smile/VirtualCategories/Model/Observer.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,12 @@ public function prepareCategoryFilter(Varien_Event_Observer $observer)
6363
// Append the query string for the virtual categories
6464
$queryString = $this->_getVirtualRule($category)->getSearchQuery();
6565

66+
// Append the query string for the parent category : ie the current one.
6667
if ($parentCategory->getId() !== $category->getId()) {
67-
$parentCategoryQuery = $this->_getVirtualRule($parentCategory)->getSearchQuery($category->getId());
68-
$queryString = implode(' AND ', array_filter(array_merge(array($queryString), array("(" . $parentCategoryQuery . ")" ))));
68+
$parentCategoryQuery = $this->_getVirtualRule($parentCategory)->getSearchQuery();
69+
if ($parentCategoryQuery) {
70+
$queryString = implode(' AND ', array_filter(array_merge(array("(" .$queryString . ")"), array("(" . $parentCategoryQuery . ")"))));
71+
}
6972
$observer->getFilter()->setUseUrlRewrites(false);
7073
}
7174

@@ -102,6 +105,7 @@ public function prepareCategoryFacet(Varien_Event_Observer $observer)
102105
$queries = $this->_getVirtualRule($category)->getChildrenCategoryQueries($observer->getCategory()->getId(), false, 1);
103106

104107
$options = array('queries' => $queries, 'prefix' => 'categories_');
108+
105109
$query->addFacet('categories', 'queryGroup', $options);
106110
$filter->setProductCollectionFacetSet(true);
107111

src/app/code/community/Smile/VirtualCategories/Model/Rule.php

Lines changed: 95 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,65 @@ public function getConditionsInstance()
7777
return Mage::getModel('smile_virtualcategories/rule_condition_combine');
7878
}
7979

80+
/**
81+
* @param string $cacheKey The cache key
82+
* @param array $data The data to cache
83+
*
84+
* @return $this
85+
*/
86+
public function addToStaticCacheInstance($cacheKey, $data)
87+
{
88+
$this->_queryCache[$cacheKey] = $data;
89+
90+
return $this;
91+
}
92+
93+
/**
94+
* @param string $cacheKey The cache key
95+
*
96+
* @return bool|array
97+
*/
98+
public function getFromStaticCacheInstance($cacheKey)
99+
{
100+
$data = false;
101+
102+
if (isset($this->_queryCache[$cacheKey]) && ($this->_queryCache[$cacheKey] !== null)) {
103+
$data = $this->_queryCache[$cacheKey];
104+
}
105+
106+
return $data;
107+
}
108+
80109
/**
81110
* Local caching of queries. Used when a category query is retrieved several times during the same request.
82111
*
83-
* @param int $categoryId Id of the category.
112+
* @param int $categoryId Id of the category.
113+
* @param array $excludedIds Excluded category ids, if any.
84114
*
85115
* @return NULL|string
86116
*/
87-
public function getQueryFromCache($categoryId)
117+
public function getQueryFromCache($categoryId, $excludedIds = array())
88118
{
119+
/** @var Smile_VirtualCategories_Model_Rule $cacheInstance */
89120
$cacheInstance = Mage::getSingleton('smile_virtualcategories/rule');
90-
$data = false;
91-
92-
if (isset($cacheInstance->_queryCache[$categoryId])) {
93-
$data = $cacheInstance->_queryCache[$categoryId];
121+
$cacheKey = $this->forgeCacheKey($categoryId, $excludedIds);
122+
$data = false;
123+
124+
Mage::log("CACHE READ : " . $cacheKey, null, "rule-cache.log");
125+
if ($cacheInstance->getFromStaticCacheInstance($cacheKey)) {
126+
$data = $cacheInstance->getFromStaticCacheInstance($cacheKey);
127+
$this->cacheQuery($categoryId, $data, $excludedIds);
128+
Mage::log("CACHE FOUND [STATIC]", null, "rule-cache.log");
94129
}
95130

96-
if ($data === false && $cacheData = Mage::app()->loadCache(self::CACHE_KEY_PREFIX . '_' .$categoryId)) {
131+
if ($data === false && $cacheData = Mage::app()->loadCache($cacheKey)) {
97132
$data = unserialize($cacheData);
133+
$cacheInstance->addToStaticCacheInstance($cacheKey, $data);
134+
Mage::log("CACHE FOUND [BACKEND]", null, "rule-cache.log");
135+
}
136+
137+
if ($data == false) {
138+
Mage::log("CACHE NOT FOUND ", null, "rule-cache.log");
98139
}
99140

100141
return $data;
@@ -103,24 +144,27 @@ public function getQueryFromCache($categoryId)
103144
/**
104145
* Store category query into the local cache.
105146
*
106-
* @param int $categoryId Id of the category.
107-
* @param string $data Data to cache [query, used_categories].
147+
* @param int $categoryId Id of the category.
148+
* @param string $data Data to cache [query, used_categories].
149+
* @param array $excludedIds Excluded category ids, if any.
108150
*
109151
* @return Smile_VirtualCategories_Model_Rule
110152
*/
111-
public function cacheQuery($categoryId, $data)
153+
public function cacheQuery($categoryId, $data, $excludedIds = array())
112154
{
155+
$cacheKey = $this->forgeCacheKey($categoryId, $excludedIds);
156+
157+
/** @var Smile_VirtualCategories_Model_Rule $cacheInstance */
113158
$cacheInstance = Mage::getSingleton('smile_virtualcategories/rule');
114-
$cacheInstance->_queryCache[$categoryId] = $data;
159+
$cacheInstance->addToStaticCacheInstance($cacheKey, $data);
115160

116161
$cacheTags = array();
117162
foreach ($data[1] as $usedCategoryId) {
118163
$cacheTags[] = Mage_Catalog_Model_Category::CACHE_TAG . '_' . $usedCategoryId;
119164
}
120165

121-
$cacheId = self::CACHE_KEY_PREFIX . '_' .$categoryId;
122-
123-
Mage::app()->saveCache(serialize($data), $cacheId, $cacheTags, Mage_Core_Model_Cache::DEFAULT_LIFETIME);
166+
Mage::log("CACHE WRITE : " . $cacheKey, null, "rule-cache.log");
167+
Mage::app()->saveCache(serialize($data), $cacheKey, $cacheTags, Mage_Core_Model_Cache::DEFAULT_LIFETIME);
124168

125169
return $this;
126170
}
@@ -136,12 +180,13 @@ public function getSearchQuery($excludedCategories = array())
136180
{
137181
$category = $this->getCategory();
138182

139-
$cacheData = $this->getQueryFromCache($category->getId() . $category->getStoreId());
183+
$cacheData = $this->getQueryFromCache($category->getId() . "_" . $category->getStoreId(), $excludedCategories);
140184
$query = '';
141185

142-
if (!$cacheData || (!empty($excludedCategories))) {
143-
$this->_usedCategories = array();
186+
if (!$cacheData) {
187+
144188
$this->addUsedCategoryIds($category->getId());
189+
145190
if ($category->getIsVirtual()) {
146191
$this->getConditions()->setRule($this);
147192
$query = $this->getConditions()->getSearchQuery($excludedCategories);
@@ -151,18 +196,12 @@ public function getSearchQuery($excludedCategories = array())
151196
$query = implode(' OR ', array_merge(array($query), $childrenQueries));
152197
}
153198

154-
// Append the root category query string if needed
155-
if ($rootCategory = Mage::helper('smile_virtualcategories')->getVirtualRootCategory($category)) {
156-
$rootCategoryQuery = $this->_getVirtualRule($rootCategory)->getSearchQuery($category->getId());
157-
$query = implode(' AND ', array_filter(array_merge(array($query), array("(" . $rootCategoryQuery . ")"))));
158-
}
199+
$this->cacheQuery($category->getId() . "_" . $category->getStoreId(), array($query, $this->_usedCategories), $excludedCategories);
159200

160-
if (empty($excludedCategories)) {
161-
$this->cacheQuery($category->getId() . $category->getStoreId(), array($query, $this->_usedCategories));
162-
}
163201
} else {
164202
list($query, $this->_usedCategories) = $cacheData;
165203
}
204+
166205
return $query;
167206
}
168207

@@ -188,7 +227,7 @@ public function getChildrenCategoryQueries($excludedCategories = array(), $onlyV
188227
->setStore($rootCategory->getStoreId())
189228
->addIsActiveFilter()
190229
->addFieldToFilter('path', array('like' => $rootCategory->getPath() . '/%'))
191-
->addAttributeToSelect('virtual_category');
230+
->addAttributeToSelect(array('virtual_category', 'name'));
192231

193232
if (!empty($excludedCategories)) {
194233
$categories->addFieldToFilter('entity_id', array('nin' => $excludedCategories));
@@ -200,17 +239,12 @@ public function getChildrenCategoryQueries($excludedCategories = array(), $onlyV
200239

201240
foreach ($categories as $currentCategory) {
202241
if ($currentCategory->getIsVirtual() || ($onlyVirtual == false)) {
242+
203243
$virtualRule = $currentCategory->getVirtualRule();
204244
$virtualRule->setStoreId($this->getCategory()->getStoreId());
205245
$query = $virtualRule->getSearchQuery($excludedCategories);
206-
if ($query) {
207-
208-
// Append the root category query string if needed
209-
if ($rootCategory = Mage::helper('smile_virtualcategories')->getVirtualRootCategory($currentCategory)) {
210-
$rootCategoryQuery = $this->_getVirtualRule($rootCategory)->getSearchQuery($currentCategory->getId());
211-
$query = implode(' AND ', array_filter(array_merge(array($query), array("(" . $rootCategoryQuery . ")" ))));
212-
}
213246

247+
if ($query) {
214248
$queries[$currentCategory->getId()] = '(' . $query . ')';
215249
$this->addUsedCategoryIds($virtualRule->getUsedCategoryIds());
216250
}
@@ -291,4 +325,32 @@ protected function _getVirtualRule($category)
291325
{
292326
return Mage::helper('smile_virtualcategories')->getVirtualRule($category);
293327
}
328+
329+
/**
330+
* Retrieve proper cache key for a given string
331+
*
332+
* @param string $identifier The object identifier to forge cache key for
333+
* @param array $additional An additional array of object ids to add to the cache key.
334+
*
335+
* @return string
336+
*/
337+
private function forgeCacheKey($identifier, $additional = array())
338+
{
339+
$cacheKey = (string) $identifier;
340+
$cacheKey = self::CACHE_KEY_PREFIX . "_" . $cacheKey;
341+
342+
if (!is_array($additional)) {
343+
$additional = array($additional);
344+
}
345+
346+
$additional = array_filter($additional);
347+
348+
if (!empty($additional)) {
349+
$additional = array_unique($additional);
350+
sort($additional);
351+
$cacheKey .= "_" . implode("|", $additional);
352+
}
353+
354+
return $cacheKey;
355+
}
294356
}

src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Combine.php

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,16 @@
1818
*/
1919
class Smile_VirtualCategories_Model_Rule_Condition_Combine extends Mage_CatalogRule_Model_Rule_Condition_Combine
2020
{
21+
/**
22+
* Class constructor
23+
* Set proper type to prevent overriding by parent class
24+
*/
25+
public function __construct()
26+
{
27+
parent::__construct();
28+
$this->setType('smile_virtualcategories/rule_condition_combine');
29+
}
30+
2131
/**
2232
* List all available rules under a combine.
2333
*
@@ -60,12 +70,11 @@ public function getNewChildSelectOptions()
6070
*/
6171
public function getSearchQuery($excludedCategories = array())
6272
{
63-
$operator = 'must';
64-
6573
$ruleOperator = $this->getAggregator();
6674
$ruleValue = $this->getValue();
6775

6876
$conditions = array();
77+
6978
foreach ($this->getConditions() as $condition) {
7079
$condition->setRule($this->getRule());
7180
$conditions[] = $condition->getSearchQuery($excludedCategories);
@@ -76,16 +85,16 @@ public function getSearchQuery($excludedCategories = array())
7685

7786
if (!empty($conditions)) {
7887
if ($ruleOperator == 'any' && $ruleValue == '1') {
79-
$query = implode(' OR ', $conditions);
80-
} elseif ($ruleOperator == 'any' && $ruleValue = '0') {
88+
$query = '(' . implode(' OR ', $conditions) . ')';
89+
} elseif ($ruleOperator == 'any' && $ruleValue == '0') {
8190
$query = '-(' . implode(' AND ', $conditions) . ')';
82-
} elseif ($ruleOperator == 'all' && $ruleValue = '1') {
83-
$query = implode(' AND ', $conditions);
84-
} elseif ($ruleOperator == 'all' && $ruleValue = '0') {
91+
} elseif ($ruleOperator == 'all' && $ruleValue == '1') {
92+
$query = '(' . implode(' AND ', $conditions) . ')';
93+
} elseif ($ruleOperator == 'all' && $ruleValue == '0') {
8594
$query = '-(' . implode(' OR ', $conditions) . ')';
8695
}
8796
}
8897

8998
return $query;
9099
}
91-
}
100+
}

src/app/code/community/Smile/VirtualCategories/Model/Rule/Condition/Product.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ protected function _getCategoriesSearchQuery($value, $not = false, $excludedCate
113113
$query[] = $subQuery;
114114
}
115115
}
116+
$query = array_filter($query);
116117
if (!empty($query)) {
117118
$query = '(' . implode(' OR ', $query) . ')';
118119
$query = $not == true ? '-' . $query : $query;

src/app/code/community/Smile/VirtualCategories/controllers/Adminhtml/Catalog/CategoryController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ public function previewAction()
3232
$storeId = $this->getRequest()->getParam('store', false);
3333

3434
if ($data = $this->getRequest()->getPost()) {
35-
$model->addData($data['general']);
35+
if (isset($data['general']) && (is_array($data['general']))) {
36+
$model->addData($data['general']);
37+
}
3638
}
3739

3840
if ($storeId) {

0 commit comments

Comments
 (0)