File indexing completed on 2025-05-04 05:29:13
0001 <?php 0002 0003 /** 0004 * ocs-webserver 0005 * 0006 * Copyright 2016 by pling GmbH. 0007 * 0008 * This file is part of ocs-webserver. 0009 * 0010 * This program is free software: you can redistribute it and/or modify 0011 * it under the terms of the GNU Affero General Public License as 0012 * published by the Free Software Foundation, either version 3 of the 0013 * License, or (at your option) any later version. 0014 * 0015 * This program is distributed in the hope that it will be useful, 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0018 * GNU Affero General Public License for more details. 0019 * 0020 * You should have received a copy of the GNU Affero General Public License 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0022 **/ 0023 class Default_Model_ProjectCategory 0024 { 0025 const CACHE_TREE_STORE = 'store_cat_tree'; 0026 const CACHE_TREE_SECTION = 'section_cat_tree'; 0027 0028 /** @var string */ 0029 protected $_dataTableName; 0030 /** @var Default_Model_DbTable_ProjectCategory */ 0031 protected $_dataTable; 0032 0033 /** 0034 * PHP 5 allows developers to declare constructor methods for classes. 0035 * Classes which have a constructor method call this method on each newly-created object, 0036 * so it is suitable for any initialization that the object may need before it is used. 0037 * 0038 * Note: Parent constructors are not called implicitly if the child class defines a constructor. 0039 * In order to run a parent constructor, a call to parent::__construct() within the child constructor is required. 0040 * 0041 * param [ mixed $args [, $... ]] 0042 * 0043 * @param string $_dataTableName 0044 * 0045 * @link http://php.net/manual/en/language.oop5.decon.php 0046 */ 0047 public function __construct($_dataTableName = 'Default_Model_DbTable_ProjectCategory') 0048 { 0049 $this->_dataTableName = $_dataTableName; 0050 $this->_dataTable = new $this->_dataTableName; 0051 } 0052 0053 /** 0054 * @param null $store_id 0055 * 0056 * @return array 0057 * @throws Zend_Cache_Exception 0058 * @throws Zend_Exception 0059 */ 0060 public function fetchTreeForView($store_id = null) 0061 { 0062 $tags = null; 0063 0064 if (empty($store_id)) { 0065 $store_config = Zend_Registry::get('store_config'); 0066 $store_id = $store_config->store_id; 0067 $tags = Zend_Registry::isRegistered('config_store_tags') ? Zend_Registry::get('config_store_tags') : array(); 0068 } 0069 0070 /** @var Zend_Cache_Core $cache */ 0071 $cache = Zend_Registry::get('cache'); 0072 $cache_id = __CLASS__ . '_' . __FUNCTION__ . "_{$store_id}"; 0073 0074 $tree = $cache->load($cache_id); 0075 0076 if (false === $tree OR empty($tree)) { 0077 try { 0078 $rows = $this->fetchCategoryTreeWithTags($store_id, $tags); 0079 } catch (Zend_Exception $e) { 0080 Zend_Registry::get('logger')->err(__METHOD__ . ' - can not fetch categories : ' . $e->getMessage()); 0081 $modelCategories = new Default_Model_DbTable_ConfigStore(); 0082 $defaultStore = $modelCategories->fetchDefaultStoreId(); 0083 $rows = $this->fetchCategoryTreeWithTags($defaultStore->store_id, $tags); 0084 } 0085 0086 list($rows, $tree) = $this->buildTreeForView($rows); 0087 $cache->save($tree, $cache_id, array(), 120); 0088 } 0089 0090 return $tree; 0091 } 0092 0093 0094 /** 0095 * @param null $store_id 0096 * 0097 * @return array 0098 * @throws Zend_Cache_Exception 0099 * @throws Zend_Exception 0100 */ 0101 public function fetchTreeForViewForProjectFavourites($store_id = null,$member_id=null) 0102 { 0103 if (empty($store_id)) { 0104 $store_config = Zend_Registry::get('store_config'); 0105 $store_id = $store_config->store_id; 0106 } 0107 if($member_id==null) 0108 { 0109 $auth = Zend_Auth::getInstance(); 0110 if ($auth->hasIdentity()) { 0111 $this->_authMember = $auth->getStorage()->read(); 0112 $member_id = $this->_authMember->member_id; 0113 }else 0114 { 0115 return null; 0116 } 0117 } 0118 $sql = " 0119 SELECT `sct`.`lft`, `sct`.`rgt`, `sct`.`project_category_id` AS `id`, `sct`.`title`, `scpc`.`count_product` AS `product_count`, `sct`.`xdg_type`, `sct`.`name_legacy`, if(`sct`.`rgt`-`sct`.`lft` = 1, 0, 1) AS `has_children`, (SELECT `project_category_id` FROM `stat_cat_tree` AS `sct2` WHERE `sct2`.`lft` < `sct`.`lft` AND `sct2`.`rgt` > `sct`.`rgt` ORDER BY `sct2`.`rgt` - `sct`.`rgt` LIMIT 1) AS `parent_id` 0120 FROM ( 0121 SELECT `csc`.`store_id`, `csc`.`project_category_id`, `csc`.`order`, `pc`.`title`, `pc`.`lft`, `pc`.`rgt` 0122 FROM `config_store_category` AS `csc` 0123 JOIN `project_category` AS `pc` ON `pc`.`project_category_id` = `csc`.`project_category_id` 0124 WHERE `csc`.`store_id` = :store_id 0125 GROUP BY `csc`.`store_category_id` 0126 ORDER BY `csc`.`order`, `pc`.`title` 0127 0128 ) AS `cfc` 0129 JOIN `stat_cat_tree` AS `sct` ON find_in_set(`cfc`.`project_category_id`, `sct`.`ancestor_id_path`) 0130 join ( 0131 0132 SELECT 0133 sct2.project_category_id, 0134 count(distinct p.project_id) as count_product 0135 FROM stat_cat_tree as sct1 0136 JOIN stat_cat_tree as sct2 ON sct1.lft between sct2.lft AND sct2.rgt 0137 left join ( 0138 SELECT project_category_id, f.project_id 0139 from project_follower f, stat_projects p 0140 where f.project_id = p.project_id 0141 and f.member_id = :member_id 0142 ) as p on p.project_category_id = sct1.project_category_id 0143 GROUP BY sct2.project_category_id 0144 0145 ) AS `scpc` on `sct`.`project_category_id` = `scpc`.`project_category_id` 0146 WHERE cfc.store_id = :store_id 0147 ORDER BY cfc.`order`, sct.lft 0148 "; 0149 0150 $rows = $this->_dataTable->getAdapter()->fetchAll($sql,array('store_id' =>$store_id,'member_id'=>$member_id)); 0151 list($rows, $tree) = $this->buildTreeForView($rows); 0152 return $tree; 0153 } 0154 0155 0156 /** 0157 * @param null $store_id 0158 * 0159 * @return array 0160 * @throws Zend_Cache_Exception 0161 * @throws Zend_Exception 0162 */ 0163 public function fetchTreeForViewForProjectTagGroupTags($store_id = null, $storeTagFilter = null,$tagFilter=null) 0164 { 0165 if (empty($store_id)) { 0166 $store_config = Zend_Registry::get('store_config'); 0167 $store_id = $store_config->store_id; 0168 } 0169 0170 $cacheName = __FUNCTION__ . '_' . md5(serialize($storeTagFilter) . '_' . serialize($tagFilter) . '_' . serialize($store_id)); 0171 /** @var Zend_Cache_Core $cache */ 0172 $cache = Zend_Registry::get('cache'); 0173 0174 if (false === ($tree = $cache->load($cacheName))) { 0175 $filterString = ""; 0176 //Store Tag Filter 0177 if(null != $storeTagFilter) { 0178 if(is_array($storeTagFilter)) { 0179 foreach ($storeTagFilter as $value) { 0180 $filterString .= " AND FIND_IN_SET('".$value."',p.tag_ids)"; 0181 } 0182 } else { 0183 $filterString .= " AND FIND_IN_SET('".$storeTagFilter."',p.tag_ids)"; 0184 } 0185 } 0186 //Store-Tag-Group-Filter 0187 if (is_array($tagFilter)) { 0188 $tagList = $tagFilter; 0189 foreach ($tagList as $key => $value) { 0190 if($value != null && $value != "0") { 0191 $filterString .= " AND FIND_IN_SET('".$value."',p.tag_ids)"; 0192 } 0193 } 0194 } else { 0195 $filterString .= " AND FIND_IN_SET('".$tagFilter."',p.tag_ids)"; 0196 } 0197 0198 $sql = " 0199 SELECT `sct`.`lft`, `sct`.`rgt`, `sct`.`project_category_id` AS `id`, `sct`.`title`, `scpc`.`count_product` AS `product_count`, `sct`.`xdg_type`, `sct`.`name_legacy`, if(`sct`.`rgt`-`sct`.`lft` = 1, 0, 1) AS `has_children`, (SELECT `project_category_id` FROM `stat_cat_tree` AS `sct2` WHERE `sct2`.`lft` < `sct`.`lft` AND `sct2`.`rgt` > `sct`.`rgt` ORDER BY `sct2`.`rgt` - `sct`.`rgt` LIMIT 1) AS `parent_id` 0200 FROM ( 0201 SELECT `csc`.`store_id`, `csc`.`project_category_id`, `csc`.`order`, `pc`.`title`, `pc`.`lft`, `pc`.`rgt` 0202 FROM `config_store_category` AS `csc` 0203 JOIN `project_category` AS `pc` ON `pc`.`project_category_id` = `csc`.`project_category_id` 0204 WHERE `csc`.`store_id` = :store_id 0205 GROUP BY `csc`.`store_category_id` 0206 ORDER BY `csc`.`order`, `pc`.`title` 0207 0208 ) AS `cfc` 0209 JOIN `stat_cat_tree` AS `sct` ON find_in_set(`cfc`.`project_category_id`, `sct`.`ancestor_id_path`) 0210 join ( 0211 0212 SELECT 0213 sct2.project_category_id, 0214 count(distinct p.project_id) as count_product 0215 FROM stat_cat_tree as sct1 0216 JOIN stat_cat_tree as sct2 ON sct1.lft between sct2.lft AND sct2.rgt 0217 left join ( 0218 SELECT project_category_id, project_id 0219 from stat_projects p 0220 WHERE 1=1 0221 ".$filterString." 0222 ) as p on p.project_category_id = sct1.project_category_id 0223 GROUP BY sct2.project_category_id 0224 0225 ) AS `scpc` on `sct`.`project_category_id` = `scpc`.`project_category_id` 0226 WHERE cfc.store_id = :store_id 0227 ORDER BY cfc.`order`, sct.lft 0228 "; 0229 0230 Zend_Registry::get('logger')->debug(__METHOD__ . ' - SQL: ' . $sql); 0231 0232 $rows = $this->_dataTable->getAdapter()->fetchAll($sql,array('store_id' =>$store_id)); 0233 list($rows, $tree) = $this->buildTreeForView($rows); 0234 0235 $cache->save($tree, $cacheName, array(), 1800); 0236 } 0237 return $tree; 0238 } 0239 0240 0241 0242 /** 0243 * @param int|null $store_id 0244 * @param string|null $tags 0245 * 0246 * @return array 0247 * @throws Zend_Exception 0248 */ 0249 protected function fetchCategoryTreeWithTags($store_id = null, $tags = null) 0250 { 0251 if (empty($store_id)) { 0252 return array(); 0253 } 0254 0255 Zend_Registry::get('logger')->debug(__METHOD__ . ' - ' . $store_id . ' - ' . json_encode($tags)); 0256 0257 if (empty($tags)) { 0258 $statement = $this->_dataTable->getAdapter()->query("CALL fetchCatTreeForStore(:store_id)", array("store_id" => $store_id)); 0259 } else { 0260 $statement = $this->_dataTable->getAdapter()->query("CALL fetchCatTreeWithTagsForStore(:store_id,:tagids)", array("store_id"=>$store_id, "tagids" => implode(',',$tags))); 0261 } 0262 0263 $result = $statement->fetchAll(); 0264 0265 // if (count($result) == 0) { 0266 // throw new Zend_Exception('no categories could be found for store id: ' . $store_id); 0267 // } 0268 0269 return $result; 0270 } 0271 0272 /** 0273 * @param array $rows 0274 * @param int|null $parent_id 0275 * 0276 * @return array 0277 */ 0278 protected function buildTreeForView($rows, $parent_id = null) 0279 { 0280 $result = array(); 0281 $rememberParent = null; 0282 0283 while (false === empty($rows)) { 0284 $row = array_shift($rows); 0285 0286 $result_element = array( 0287 'id' => $row['id'], 0288 'title' => $row['title'], 0289 'product_count' => $row['product_count'], 0290 'xdg_type' => $row['xdg_type'], 0291 'name_legacy' => $row['name_legacy'], 0292 'has_children' => $row['has_children'], 0293 'parent_id' => $row['parent_id'] 0294 ); 0295 0296 //has children? 0297 if ($row['has_children'] == 1) { 0298 $result_element['has_children'] = true; 0299 $rememberParent = $row['id']; 0300 list($rows, $children) = $this->buildTreeForView($rows, $rememberParent); 0301 uasort($children, function ($a, $b) {return strcasecmp($a['title'], $b['title']);}); 0302 $result_element['children'] = $children; 0303 $rememberParent = null; 0304 } 0305 0306 $result[] = $result_element; 0307 0308 if (isset($parent_id) AND isset($rows[0]['parent_id']) AND $parent_id != $rows[0]['parent_id']) { 0309 break; 0310 } 0311 } 0312 0313 return array($rows, $result); 0314 } 0315 0316 /** 0317 * @param int|null $store_id If not set, the tree for the current store will be returned 0318 * @param bool $clearCache 0319 * 0320 * @return array 0321 * @throws Zend_Cache_Exception 0322 * @throws Zend_Exception 0323 * @deprecated use fetchTreeForView 0324 */ 0325 public function fetchCategoryTreeForStore($store_id = null, $clearCache = false) 0326 { 0327 if (empty($store_id)) { 0328 $store_config = Zend_Registry::get('store_config'); 0329 $store_id = $store_config->store_id; 0330 } 0331 0332 /** @var Zend_Cache_Core $cache */ 0333 $cache = Zend_Registry::get('cache'); 0334 $cache_id = self::CACHE_TREE_STORE . "_{$store_id}"; 0335 0336 if ($clearCache) { 0337 $cache->remove($cache_id); 0338 } 0339 0340 if (false === ($tree = $cache->load($cache_id))) { 0341 $modelCategoryStore = new Default_Model_DbTable_ConfigStoreCategory(); 0342 $rows = $modelCategoryStore->fetchCatIdsForStore((int)$store_id); 0343 0344 if (count($rows) < 1) { 0345 $modelCategories = new Default_Model_DbTable_ProjectCategory(); 0346 $root = $modelCategories->fetchRoot(); 0347 $rows = $modelCategories->fetchImmediateChildrenIds($root['project_category_id'], $modelCategories::ORDERED_TITLE); 0348 $tree = $this->buildTree($rows, null, null); 0349 } else { 0350 $tree = $this->buildTree($rows, null, (int)$store_id); 0351 } 0352 0353 $cache->save($tree, $cache_id, array(), 600); 0354 } 0355 0356 return $tree; 0357 } 0358 0359 /** 0360 * @param int|null $store_id If not set, the tree for the current store will be returned 0361 * @param bool $clearCache 0362 * 0363 * @return array 0364 * @throws Zend_Cache_Exception 0365 * @throws Zend_Exception 0366 * @deprecated use fetchTreeForView 0367 */ 0368 public function fetchCategoryTreeForSection($section_id = null, $clearCache = false) 0369 { 0370 /** @var Zend_Cache_Core $cache */ 0371 $cache = Zend_Registry::get('cache'); 0372 $cache_id = self::CACHE_TREE_SECTION . "_{$section_id}"; 0373 0374 if ($clearCache) { 0375 $cache->remove($cache_id); 0376 } 0377 0378 if (false === ($tree = $cache->load($cache_id))) { 0379 $modelCategoryStore = new Default_Model_DbTable_SectionCategory(); 0380 $rows = $modelCategoryStore->fetchCatIdsForSection((int)$store_id); 0381 0382 if (count($rows) < 1) { 0383 $modelCategories = new Default_Model_DbTable_ProjectCategory(); 0384 $root = $modelCategories->fetchRoot(); 0385 $rows = $modelCategories->fetchImmediateChildrenIds($root['project_category_id'], $modelCategories::ORDERED_TITLE); 0386 $tree = $this->buildTree($rows, null, null); 0387 } else { 0388 $tree = $this->buildTree($rows, null, null); 0389 } 0390 0391 $cache->save($tree, $cache_id, array(), 600); 0392 } 0393 0394 return $tree; 0395 } 0396 0397 0398 private function buildTree($list, $parent_id = null, $store_id = null) 0399 { 0400 if (false === is_array($list)) { 0401 $list = array($list); 0402 } 0403 $modelCategories = new Default_Model_DbTable_ProjectCategory(); 0404 $result = array(); 0405 foreach ($list as $cat_id) { 0406 $currentCategory = $modelCategories->fetchElement($cat_id); 0407 $countProduct = $this->fetchProductCount($cat_id, $store_id); 0408 0409 $result_element = array( 0410 'id' => $cat_id, 0411 'title' => $currentCategory['title'], 0412 'product_count' => $countProduct, 0413 'xdg_type' => $currentCategory['xdg_type'], 0414 'name_legacy' => $currentCategory['name_legacy'], 0415 'has_children' => false 0416 ); 0417 0418 if (isset($parent_id)) { 0419 $result_element['parent_id'] = $parent_id; 0420 } 0421 0422 //has children? 0423 if (($currentCategory['rgt'] - $currentCategory['lft']) > 1) { 0424 $result_element['has_children'] = true; 0425 $ids = $modelCategories->fetchImmediateChildrenIds($currentCategory['project_category_id'], 0426 $modelCategories::ORDERED_TITLE); 0427 $result_element['children'] = $this->buildTree($ids, $currentCategory['project_category_id'], $store_id); 0428 } 0429 $result[] = $result_element; 0430 } 0431 0432 return $result; 0433 } 0434 0435 private function fetchProductCount($cat_id, $store_id = null) 0436 { 0437 0438 $store_config = Zend_Registry::isRegistered('store_config') ? Zend_Registry::get('store_config') : null; 0439 $tagFilter = null; 0440 if($store_config) 0441 { 0442 $tagFilter = Zend_Registry::isRegistered('config_store_tags') ? Zend_Registry::get('config_store_tags') : null; 0443 }else 0444 { 0445 $tagFilter = null; 0446 } 0447 0448 0449 if ($tagFilter) { 0450 $sql = 0451 "SELECT count_product FROM stat_cat_prod_count WHERE project_category_id = :cat_id AND tag_id = :tags"; 0452 $bind = array('cat_id' => $cat_id, 'tags' => $tagFilter); 0453 } else { 0454 $sql = "SELECT count_product FROM stat_cat_prod_count WHERE project_category_id = :cat_id AND tag_id IS NULL"; 0455 $bind = array('cat_id' => $cat_id); 0456 } 0457 0458 $result = $this->_dataTable->getAdapter()->fetchRow($sql, $bind); 0459 0460 return (int)$result['count_product']; 0461 } 0462 0463 /** 0464 * @param bool $clearCache 0465 * 0466 * @return array|false|mixed 0467 * @throws Zend_Cache_Exception 0468 * @throws Zend_Exception 0469 * 0470 * @deprecated use fetchTreeForView 0471 */ 0472 public function fetchCategoryTreeCurrentStore($clearCache = false) 0473 { 0474 $store_config = Zend_Registry::get('store_config'); 0475 $store_id = $store_config->store_id; 0476 0477 /** @var Zend_Cache_Core $cache */ 0478 $cache = Zend_Registry::get('cache'); 0479 $cache_id = self::CACHE_TREE_STORE . "_{$store_id}"; 0480 0481 if ($clearCache) { 0482 $cache->remove($cache_id); 0483 } 0484 0485 if (false === ($tree = $cache->load($cache_id))) { 0486 $list_cat_id = self::fetchCatIdsForCurrentStore(); 0487 $tree = $this->buildTree($list_cat_id); 0488 $cache->save($tree, $cache_id, array(), 600); 0489 } 0490 0491 return $tree; 0492 } 0493 0494 /** 0495 * @return mixed|null 0496 * @throws Zend_Exception 0497 */ 0498 public static function fetchCatIdsForCurrentStore() 0499 { 0500 return Zend_Registry::isRegistered('store_category_list') ? Zend_Registry::get('store_category_list') : null; 0501 } 0502 0503 /** 0504 * @return array 0505 * @throws Zend_Exception 0506 */ 0507 public function fetchCatNamesForCurrentStore() 0508 { 0509 $list_cat_id = self::fetchCatIdsForCurrentStore(); 0510 0511 $sql = "SELECT project_category_id, title FROM project_category WHERE project_category_id IN (" . implode(',', $list_cat_id) 0512 . ")"; 0513 0514 $result = $this->_dataTable->getAdapter()->fetchPairs($sql); 0515 0516 return $result; 0517 } 0518 0519 /** 0520 * @return array 0521 * @throws Zend_Exception 0522 */ 0523 public function fetchCatNamesForID($list_cat_id) 0524 { 0525 0526 $sql = "SELECT title FROM project_category WHERE project_category_id IN (" . implode(',', $list_cat_id) 0527 . ") order by title " ; 0528 0529 $results = $this->_dataTable->getAdapter()->fetchAll($sql); 0530 $values = array_map(function($row) { return $row['title']; }, $results); 0531 return $values; 0532 } 0533 0534 0535 /** 0536 * @return array 0537 */ 0538 public function fetchCatNames() 0539 { 0540 $sql = "SELECT project_category_id, title FROM project_category"; 0541 0542 $result = $this->_dataTable->getAdapter()->fetchPairs($sql); 0543 0544 return $result; 0545 } 0546 0547 }