00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 class Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Tree extends Varien_Data_Tree_Dbp
00036 {
00037
00038
00039
00040
00041
00042
00043 protected $_collection;
00044
00045
00046
00047
00048
00049
00050 protected $_isActiveAttributeId = null;
00051
00052 protected $_joinUrlRewriteIntoCollection = false;
00053
00054
00055
00056
00057
00058
00059 protected $_inactiveCategoryIds = null;
00060
00061
00062
00063
00064
00065 public function __construct()
00066 {
00067 $resource = Mage::getSingleton('core/resource');
00068
00069 parent::__construct(
00070 $resource->getConnection('catalog_read'),
00071 $resource->getTableName('catalog/category'),
00072 array(
00073 Varien_Data_Tree_Dbp::ID_FIELD => 'entity_id',
00074 Varien_Data_Tree_Dbp::PATH_FIELD => 'path',
00075 Varien_Data_Tree_Dbp::ORDER_FIELD => 'position',
00076 Varien_Data_Tree_Dbp::LEVEL_FIELD => 'level',
00077 )
00078 );
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088 public function addCollectionData($collection=null, $sorted=false, $exclude=array(), $toLoad=true, $onlyActive = false)
00089 {
00090 if (is_null($collection)) {
00091 $collection = $this->getCollection($sorted);
00092 } else {
00093 $this->setCollection($collection);
00094 }
00095
00096 if (!is_array($exclude)) {
00097 $exclude = array($exclude);
00098 }
00099
00100 $collection->initCache(
00101 Mage::app()->getCache(),
00102 'tree',
00103 array(Mage_Catalog_Model_Category::CACHE_TAG)
00104 );
00105
00106 $nodeIds = array();
00107 foreach ($this->getNodes() as $node) {
00108 if (!in_array($node->getId(), $exclude)) {
00109 $nodeIds[] = $node->getId();
00110 }
00111 }
00112 $collection->addIdFilter($nodeIds);
00113 if ($onlyActive) {
00114
00115 $disabledIds = $this->_getDisabledIds($collection);
00116 if ($disabledIds) {
00117 $collection->addFieldToFilter('entity_id', array('nin'=>$disabledIds));
00118 }
00119 $collection->addAttributeToFilter('is_active', 1);
00120 }
00121
00122 if ($this->_joinUrlRewriteIntoCollection) {
00123 $collection->joinUrlRewrite();
00124 $this->_joinUrlRewriteIntoCollection = false;
00125 }
00126
00127 if($toLoad) {
00128 $collection->load();
00129
00130 foreach ($collection as $category) {
00131 if ($this->getNodeById($category->getId())) {
00132 $this->getNodeById($category->getId())
00133 ->addData($category->getData());
00134 }
00135 }
00136
00137
00138 foreach ($this->getNodes() as $node) {
00139 if (!$collection->getItemById($node->getId()) && $node->getParent()) {
00140 $this->removeNode($node);
00141 }
00142 }
00143 }
00144
00145 return $this;
00146 }
00147
00148
00149
00150
00151
00152
00153 public function addInactiveCategoryIds($ids)
00154 {
00155 if (!is_array($this->_inactiveCategoryIds)) {
00156 $this->_initInactiveCategoryIds();
00157 }
00158 $this->_inactiveCategoryIds = array_merge($ids, $this->_inactiveCategoryIds);
00159 return $this;
00160 }
00161
00162
00163
00164
00165
00166
00167 protected function _initInactiveCategoryIds()
00168 {
00169 $this->_inactiveCategoryIds = array();
00170 Mage::dispatchEvent('catalog_category_tree_init_inactive_category_ids', array('tree'=>$this));
00171 return $this;
00172 }
00173
00174
00175
00176
00177
00178
00179 public function getInactiveCategoryIds()
00180 {
00181 if (!is_array($this->_inactiveCategoryIds)) {
00182 $this->_initInactiveCategoryIds();
00183 }
00184
00185 return $this->_inactiveCategoryIds;
00186 }
00187
00188 protected function _getDisabledIds($collection)
00189 {
00190 $storeId = Mage::app()->getStore()->getId();
00191
00192 $this->_inactiveItems = $this->getInactiveCategoryIds();
00193
00194
00195 $this->_inactiveItems = array_merge(
00196 $this->_getInactiveItemIds($collection, $storeId),
00197 $this->_inactiveItems
00198 );
00199
00200
00201 $allIds = $collection->getAllIds();
00202 $disabledIds = array();
00203
00204 foreach ($allIds as $id) {
00205 $parents = $this->getNodeById($id)->getPath();
00206 foreach ($parents as $parent) {
00207 if (!$this->_getItemIsActive($parent->getId(), $storeId)){
00208 $disabledIds[] = $id;
00209 continue;
00210 }
00211 }
00212 }
00213 return $disabledIds;
00214 }
00215
00216 protected function _getIsActiveAttributeId()
00217 {
00218 if (is_null($this->_isActiveAttributeId)) {
00219 $select = $this->_conn->select()
00220 ->from(array('a'=>Mage::getSingleton('core/resource')->getTableName('eav/attribute')), array('attribute_id'))
00221 ->join(array('t'=>Mage::getSingleton('core/resource')->getTableName('eav/entity_type')), 'a.entity_type_id = t.entity_type_id')
00222 ->where('entity_type_code = ?', 'catalog_category')
00223 ->where('attribute_code = ?', 'is_active');
00224
00225 $this->_isActiveAttributeId = $this->_conn->fetchOne($select);
00226 }
00227 return $this->_isActiveAttributeId;
00228 }
00229
00230 protected function _getInactiveItemIds($collection, $storeId)
00231 {
00232 $filter = $collection->getAllIdsSql();
00233 $attributeId = $this->_getIsActiveAttributeId();
00234
00235 $table = Mage::getSingleton('core/resource')->getTableName('catalog/category') . '_int';
00236 $select = $this->_conn->select()
00237 ->from(array('d'=>$table), array('d.entity_id'))
00238 ->where('d.attribute_id = ?', $attributeId)
00239 ->where('d.store_id = ?', 0)
00240 ->where('d.entity_id IN (?)', new Zend_Db_Expr($filter))
00241 ->joinLeft(array('c'=>$table), "c.attribute_id = '{$attributeId}' AND c.store_id = '{$storeId}' AND c.entity_id = d.entity_id", array())
00242 ->where('IFNULL(c.value, d.value) = ?', 0);
00243
00244 return $this->_conn->fetchCol($select);
00245 }
00246
00247 protected function _getItemIsActive($id)
00248 {
00249 if (!in_array($id, $this->_inactiveItems)) {
00250 return true;
00251 }
00252 return false;
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262 public function getCollection($sorted=false)
00263 {
00264 if (is_null($this->_collection)) {
00265 $this->_collection = $this->_getDefaultCollection($sorted);
00266 }
00267 return $this->_collection;
00268 }
00269
00270
00271
00272
00273
00274
00275
00276 public function setCollection($collection)
00277 {
00278 if (!is_null($this->_collection)) {
00279 destruct($this->_collection);
00280 }
00281 $this->_collection = $collection;
00282 return $this;
00283 }
00284
00285
00286
00287
00288
00289
00290
00291 protected function _getDefaultCollection($sorted=false)
00292 {
00293 $this->_joinUrlRewriteIntoCollection = true;
00294 $collection = Mage::getModel('catalog/category')->getCollection();
00295
00296
00297 $collection->addAttributeToSelect('name')
00298 ->addAttributeToSelect('url_key')
00299 ->addAttributeToSelect('is_active');
00300
00301 if ($sorted) {
00302 if (is_string($sorted)) {
00303
00304 $collection->addAttributeToSort($sorted);
00305 } else {
00306 $collection->addAttributeToSort('name');
00307 }
00308 }
00309
00310 return $collection;
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 protected function _beforeMove($category, $newParent, $prevNode)
00323 {
00324 Mage::dispatchEvent('catalog_category_tree_move_before',
00325 array(
00326 'category' => $category,
00327 'prev_parent' => $prevNode,
00328 'parent' => $newParent
00329 ));
00330
00331 return $this;
00332 }
00333
00334
00335
00336
00337
00338 public function move($category, $newParent, $prevNode = null) {
00339
00340 $this->_beforeMove($category, $newParent, $prevNode);
00341 Mage::getResourceSingleton('catalog/category')->move($category->getId(), $newParent->getId());
00342 parent::move($category, $newParent, $prevNode);
00343
00344 $this->_afterMove($category, $newParent, $prevNode);
00345 }
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 protected function _afterMove($category, $newParent, $prevNode)
00356 {
00357 Mage::app()->cleanCache(array(Mage_Catalog_Model_Category::CACHE_TAG));
00358
00359 Mage::dispatchEvent('catalog_category_tree_move_after',
00360 array(
00361 'category' => $category,
00362 'prev_node' => $prevNode,
00363 'parent' => $newParent
00364 ));
00365
00366 return $this;
00367 }
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 public function loadByIds($ids, $addCollectionData = true, $updateAnchorProductCount = true)
00378 {
00379
00380 if (empty($ids)) {
00381 $select = $this->_conn->select()
00382 ->from($this->_table, 'entity_id')
00383 ->where('`level` <= 2');
00384 $ids = $this->_conn->fetchCol($select);
00385 }
00386 if (!is_array($ids)) {
00387 $ids = array($ids);
00388 }
00389 foreach ($ids as $key => $id) {
00390 $ids[$key] = (int)$id;
00391 }
00392
00393
00394 $select = $this->_conn->select()
00395 ->from($this->_table, array('path', 'level'))
00396 ->where(sprintf('entity_id IN (%s)', implode(', ', $ids)));
00397 $where = array('`level`=0' => true);
00398 foreach ($this->_conn->fetchAll($select) as $item) {
00399 $path = explode('/', $item['path']);
00400 $level = (int)$item['level'];
00401 while ($level > 0) {
00402 $path[count($path) - 1] = '%';
00403 $where[sprintf("`level`=%d AND `path` LIKE '%s'", $level, implode('/', $path))] = true;
00404 array_pop($path);
00405 $level--;
00406 }
00407 }
00408 $where = array_keys($where);
00409
00410
00411 if ($addCollectionData) {
00412 $select = $this->_createCollectionDataSelect();
00413 }
00414 else {
00415 $select = clone $this->_select;
00416 $select->order($this->_orderField . ' ASC');
00417 }
00418 $select->where(implode(' OR ', $where));
00419
00420
00421 $arrNodes = $this->_conn->fetchAll($select);
00422 if (!$arrNodes) {
00423 return false;
00424 }
00425 if ($updateAnchorProductCount) {
00426 $this->_updateAnchorProductCount($arrNodes);
00427 }
00428 $childrenItems = array();
00429 foreach ($arrNodes as $key => $nodeInfo) {
00430 $pathToParent = explode('/', $nodeInfo[$this->_pathField]);
00431 array_pop($pathToParent);
00432 $pathToParent = implode('/', $pathToParent);
00433 $childrenItems[$pathToParent][] = $nodeInfo;
00434 }
00435 $this->addChildNodes($childrenItems, '', null);
00436
00437 return $this;
00438 }
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 public function loadBreadcrumbsArray($path, $addCollectionData = true, $withRootNode = false)
00449 {
00450 $path = explode('/', $path);
00451 if (!$withRootNode) {
00452 array_shift($path);
00453 }
00454 $result = array();
00455 if (!empty($path)) {
00456 if ($addCollectionData) {
00457 $select = $this->_createCollectionDataSelect(false);
00458 }
00459 else {
00460 $select = clone $this->_select;
00461 }
00462 $select->where(sprintf('e.entity_id IN (%s)', implode(', ', $path)))
00463 ->order(new Zend_Db_Expr('LENGTH(e.path) ASC'));
00464 $result = $this->_conn->fetchAll($select);
00465 $this->_updateAnchorProductCount($result);
00466 }
00467 return $result;
00468 }
00469
00470
00471
00472
00473
00474
00475 protected function _updateAnchorProductCount(&$data)
00476 {
00477 foreach ($data as $key => $row) {
00478 if (0 === (int)$row['is_anchor']) {
00479 $data[$key]['product_count'] = $row['self_product_count'];
00480 }
00481 }
00482 }
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 protected function _createCollectionDataSelect($sorted = true, $optionalAttributes = array())
00497 {
00498 $select = $this->_getDefaultCollection($sorted ? $this->_orderField : false)
00499 ->getSelect();
00500
00501 $attributes = array('name', 'is_active', 'is_anchor');
00502 if ($optionalAttributes) {
00503 $attributes = array_unique(array_merge($attributes, $optionalAttributes));
00504 }
00505 foreach ($attributes as $attributeCode) {
00506 $attribute = Mage::getResourceSingleton('catalog/category')->getAttribute($attributeCode);
00507
00508 if (!$attribute->getBackend()->isStatic()) {
00509 $tableAs = "_$attributeCode";
00510 $select->joinLeft(
00511 array($tableAs => $attribute->getBackend()->getTable()),
00512 sprintf('`%1$s`.entity_id=e.entity_id AND `%1$s`.attribute_id=%2$d AND `%1$s`.entity_type_id=e.entity_type_id AND `%1$s`.store_id=%3$d',
00513 $tableAs, $attribute->getData('attribute_id'), Mage_Core_Model_App::ADMIN_STORE_ID
00514 ),
00515 array($attributeCode => 'value')
00516 );
00517 }
00518 }
00519
00520
00521 $categoriesTable = Mage::getSingleton('core/resource')->getTableName('catalog/category');
00522 $categoriesProductsTable = Mage::getSingleton('core/resource')->getTableName('catalog/category_product');
00523 $select->joinLeft(array('_category_product' => $categoriesProductsTable),
00524 'e.entity_id=_category_product.category_id',
00525 array(
00526 'self_product_count' => new Zend_Db_Expr('COUNT(_category_product.product_id)'),
00527 'product_count' => new Zend_Db_Expr('(SELECT COUNT(DISTINCT cp.product_id) FROM ' . $categoriesTable . ' ee
00528 LEFT JOIN ' . $categoriesProductsTable . ' cp ON ee.entity_id=cp.category_id
00529 WHERE ee.entity_id=e.entity_id OR ee.path like CONCAT(e.path, \'/%\'))'
00530 )))
00531 ->group('e.entity_id');
00532
00533 return $select;
00534 }
00535 }