Overview

Packages

  • currencysymbol
  • MAbout
  • Mage
    • Admin
    • Adminhtml
    • AdminNotification
    • Api
    • Api2
    • Authorizenet
    • Backup
    • Bundle
    • Captcha
    • Catalog
    • CatalogIndex
    • CatalogInventory
    • CatalogRule
    • CatalogSearch
    • Centinel
    • Checkout
    • Cms
    • Compiler
    • Connect
    • Contacts
    • Core
    • Cron
    • CurrencySymbol
    • Customer
    • Dataflow
    • Directory
    • DirtectPost
    • Downloadable
    • Eav
    • GiftMessage
    • GoogleAnalytics
    • GoogleBase
    • GoogleCheckout
    • ImportExport
    • Index
    • Install
    • Log
    • Media
    • Newsletter
    • Oauth
    • Page
    • PageCache
    • Paygate
    • Payment
    • Paypal
    • PaypalUk
    • Persistent
    • Poll
    • ProductAlert
    • Rating
    • Reports
    • Review
    • Rss
    • Rule
    • Sales
    • SalesRule
    • Sedfriend
    • Sendfriend
    • Shipping
    • Sitemap
    • Tag
    • Tax
    • Usa
    • Weee
    • Widget
    • Wishlist
    • XmlConnect
  • None
  • Phoenix
    • Moneybookers
  • PHP
  • Zend
    • Date
    • Mime
    • XmlRpc

Classes

  • Mage_Catalog_Block_Breadcrumbs
  • Mage_Catalog_Block_Category_View
  • Mage_Catalog_Block_Category_Widget_Link
  • Mage_Catalog_Block_Layer_Filter_Abstract
  • Mage_Catalog_Block_Layer_Filter_Attribute
  • Mage_Catalog_Block_Layer_Filter_Category
  • Mage_Catalog_Block_Layer_Filter_Decimal
  • Mage_Catalog_Block_Layer_Filter_Price
  • Mage_Catalog_Block_Layer_State
  • Mage_Catalog_Block_Layer_View
  • Mage_Catalog_Block_Navigation
  • Mage_Catalog_Block_Product
  • Mage_Catalog_Block_Product_Abstract
  • Mage_Catalog_Block_Product_Compare_Abstract
  • Mage_Catalog_Block_Product_Compare_List
  • Mage_Catalog_Block_Product_Compare_Sidebar
  • Mage_Catalog_Block_Product_Gallery
  • Mage_Catalog_Block_Product_List
  • Mage_Catalog_Block_Product_List_Crosssell
  • Mage_Catalog_Block_Product_List_Promotion
  • Mage_Catalog_Block_Product_List_Random
  • Mage_Catalog_Block_Product_List_Related
  • Mage_Catalog_Block_Product_List_Toolbar
  • Mage_Catalog_Block_Product_List_Upsell
  • Mage_Catalog_Block_Product_New
  • Mage_Catalog_Block_Product_Price
  • Mage_Catalog_Block_Product_Price_Template
  • Mage_Catalog_Block_Product_Send
  • Mage_Catalog_Block_Product_View
  • Mage_Catalog_Block_Product_View_Abstract
  • Mage_Catalog_Block_Product_View_Additional
  • Mage_Catalog_Block_Product_View_Attributes
  • Mage_Catalog_Block_Product_View_Description
  • Mage_Catalog_Block_Product_View_Media
  • Mage_Catalog_Block_Product_View_Options
  • Mage_Catalog_Block_Product_View_Options_Abstract
  • Mage_Catalog_Block_Product_View_Options_Type_Date
  • Mage_Catalog_Block_Product_View_Options_Type_Default
  • Mage_Catalog_Block_Product_View_Options_Type_File
  • Mage_Catalog_Block_Product_View_Options_Type_Select
  • Mage_Catalog_Block_Product_View_Options_Type_Text
  • Mage_Catalog_Block_Product_View_Price
  • Mage_Catalog_Block_Product_View_Tabs
  • Mage_Catalog_Block_Product_View_Type_Configurable
  • Mage_Catalog_Block_Product_View_Type_Grouped
  • Mage_Catalog_Block_Product_View_Type_Simple
  • Mage_Catalog_Block_Product_View_Type_Virtual
  • Mage_Catalog_Block_Product_Widget_Link
  • Mage_Catalog_Block_Product_Widget_New
  • Mage_Catalog_Block_Seo_Sitemap_Abstract
  • Mage_Catalog_Block_Seo_Sitemap_Category
  • Mage_Catalog_Block_Seo_Sitemap_Product
  • Mage_Catalog_Block_Seo_Sitemap_Tree_Category
  • Mage_Catalog_Block_Widget_Link
  • Mage_Catalog_CategoryController
  • Mage_Catalog_Exception
  • Mage_Catalog_Helper_Category
  • Mage_Catalog_Helper_Category_Flat
  • Mage_Catalog_Helper_Data
  • Mage_Catalog_Helper_Image
  • Mage_Catalog_Helper_Map
  • Mage_Catalog_Helper_Output
  • Mage_Catalog_Helper_Product
  • Mage_Catalog_Helper_Product_Compare
  • Mage_Catalog_Helper_Product_Configuration
  • Mage_Catalog_Helper_Product_Flat
  • Mage_Catalog_Helper_Product_Options
  • Mage_Catalog_Helper_Product_Url
  • Mage_Catalog_Helper_Product_View
  • Mage_Catalog_IndexController
  • Mage_Catalog_Model_Abstract
  • Mage_Catalog_Model_Api2_Product
  • Mage_Catalog_Model_Api2_Product_Category
  • Mage_Catalog_Model_Api2_Product_Category_Rest
  • Mage_Catalog_Model_Api2_Product_Category_Rest_Admin_V1
  • Mage_Catalog_Model_Api2_Product_Category_Rest_Customer_V1
  • Mage_Catalog_Model_Api2_Product_Category_Rest_Guest_V1
  • Mage_Catalog_Model_Api2_Product_Image
  • Mage_Catalog_Model_Api2_Product_Image_Rest
  • Mage_Catalog_Model_Api2_Product_Image_Rest_Admin_V1
  • Mage_Catalog_Model_Api2_Product_Image_Rest_Customer_V1
  • Mage_Catalog_Model_Api2_Product_Image_Rest_Guest_V1
  • Mage_Catalog_Model_Api2_Product_Image_Validator_Image
  • Mage_Catalog_Model_Api2_Product_Rest
  • Mage_Catalog_Model_Api2_Product_Rest_Admin_V1
  • Mage_Catalog_Model_Api2_Product_Rest_Customer_V1
  • Mage_Catalog_Model_Api2_Product_Rest_Guest_V1
  • Mage_Catalog_Model_Api2_Product_Validator_Product
  • Mage_Catalog_Model_Api2_Product_Website
  • Mage_Catalog_Model_Api2_Product_Website_Rest
  • Mage_Catalog_Model_Api2_Product_Website_Rest_Admin_V1
  • Mage_Catalog_Model_Api2_Product_Website_Validator_Admin_Website
  • Mage_Catalog_Model_Api_Resource
  • Mage_Catalog_Model_Attribute_Backend_Customlayoutupdate
  • Mage_Catalog_Model_Category
  • Mage_Catalog_Model_Category_Api
  • Mage_Catalog_Model_Category_Api_V2
  • Mage_Catalog_Model_Category_Attribute_Api
  • Mage_Catalog_Model_Category_Attribute_Api_V2
  • Mage_Catalog_Model_Category_Attribute_Backend_Image
  • Mage_Catalog_Model_Category_Attribute_Backend_Sortby
  • Mage_Catalog_Model_Category_Attribute_Backend_Urlkey
  • Mage_Catalog_Model_Category_Attribute_Source_Layout
  • Mage_Catalog_Model_Category_Attribute_Source_Mode
  • Mage_Catalog_Model_Category_Attribute_Source_Page
  • Mage_Catalog_Model_Category_Attribute_Source_Sortby
  • Mage_Catalog_Model_Category_Indexer_Flat
  • Mage_Catalog_Model_Category_Indexer_Product
  • Mage_Catalog_Model_Config
  • Mage_Catalog_Model_Convert
  • Mage_Catalog_Model_Convert_Adapter_Catalog
  • Mage_Catalog_Model_Convert_Adapter_Product
  • Mage_Catalog_Model_Convert_Parser_Product
  • Mage_Catalog_Model_Design
  • Mage_Catalog_Model_Entity_Attribute
  • Mage_Catalog_Model_Entity_Product_Attribute_Frontend_Image
  • Mage_Catalog_Model_Index
  • Mage_Catalog_Model_Indexer_Url
  • Mage_Catalog_Model_Layer
  • Mage_Catalog_Model_Layer_Filter_Abstract
  • Mage_Catalog_Model_Layer_Filter_Attribute
  • Mage_Catalog_Model_Layer_Filter_Category
  • Mage_Catalog_Model_Layer_Filter_Decimal
  • Mage_Catalog_Model_Layer_Filter_Item
  • Mage_Catalog_Model_Layer_Filter_Price
  • Mage_Catalog_Model_Layer_Filter_Price_Algorithm
  • Mage_Catalog_Model_Layer_State
  • Mage_Catalog_Model_Observer
  • Mage_Catalog_Model_Product
  • Mage_Catalog_Model_Product_Action
  • Mage_Catalog_Model_Product_Api
  • Mage_Catalog_Model_Product_Api_V2
  • Mage_Catalog_Model_Product_Attribute_Api
  • Mage_Catalog_Model_Product_Attribute_Api_V2
  • Mage_Catalog_Model_Product_Attribute_Backend_Boolean
  • Mage_Catalog_Model_Product_Attribute_Backend_Groupprice
  • Mage_Catalog_Model_Product_Attribute_Backend_Groupprice_Abstract
  • Mage_Catalog_Model_Product_Attribute_Backend_Media
  • Mage_Catalog_Model_Product_Attribute_Backend_Msrp
  • Mage_Catalog_Model_Product_Attribute_Backend_Price
  • Mage_Catalog_Model_Product_Attribute_Backend_Recurring
  • Mage_Catalog_Model_Product_Attribute_Backend_Sku
  • Mage_Catalog_Model_Product_Attribute_Backend_Startdate
  • Mage_Catalog_Model_Product_Attribute_Backend_Tierprice
  • Mage_Catalog_Model_Product_Attribute_Backend_Urlkey
  • Mage_Catalog_Model_Product_Attribute_Frontend_Image
  • Mage_Catalog_Model_Product_Attribute_Group
  • Mage_Catalog_Model_Product_Attribute_Media_Api
  • Mage_Catalog_Model_Product_Attribute_Media_Api_V2
  • Mage_Catalog_Model_Product_Attribute_Set_Api
  • Mage_Catalog_Model_Product_Attribute_Set_Api_V2
  • Mage_Catalog_Model_Product_Attribute_Source_Boolean
  • Mage_Catalog_Model_Product_Attribute_Source_Countryofmanufacture
  • Mage_Catalog_Model_Product_Attribute_Source_Layout
  • Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type
  • Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type_Enabled
  • Mage_Catalog_Model_Product_Attribute_Source_Msrp_Type_Price
  • Mage_Catalog_Model_Product_Attribute_Tierprice_Api
  • Mage_Catalog_Model_Product_Attribute_Tierprice_Api_V2
  • Mage_Catalog_Model_Product_Compare_Item
  • Mage_Catalog_Model_Product_Compare_List
  • Mage_Catalog_Model_Product_Condition
  • Mage_Catalog_Model_Product_Configuration_Item_Option
  • Mage_Catalog_Model_Product_Flat_Flag
  • Mage_Catalog_Model_Product_Flat_Indexer
  • Mage_Catalog_Model_Product_Flat_Observer
  • Mage_Catalog_Model_Product_Image
  • Mage_Catalog_Model_Product_Indexer_Eav
  • Mage_Catalog_Model_Product_Indexer_Flat
  • Mage_Catalog_Model_Product_Indexer_Price
  • Mage_Catalog_Model_Product_Link
  • Mage_Catalog_Model_Product_Link_Api
  • Mage_Catalog_Model_Product_Link_Api_V2
  • Mage_Catalog_Model_Product_Media_Config
  • Mage_Catalog_Model_Product_Option
  • Mage_Catalog_Model_Product_Option_Api
  • Mage_Catalog_Model_Product_Option_Api_V2
  • Mage_Catalog_Model_Product_Option_Observer
  • Mage_Catalog_Model_Product_Option_Type_Date
  • Mage_Catalog_Model_Product_Option_Type_Default
  • Mage_Catalog_Model_Product_Option_Type_File
  • Mage_Catalog_Model_Product_Option_Type_Select
  • Mage_Catalog_Model_Product_Option_Type_Text
  • Mage_Catalog_Model_Product_Option_Value
  • Mage_Catalog_Model_Product_Option_Value_Api
  • Mage_Catalog_Model_Product_Option_Value_Api_V2
  • Mage_Catalog_Model_Product_Status
  • Mage_Catalog_Model_Product_Type
  • Mage_Catalog_Model_Product_Type_Abstract
  • Mage_Catalog_Model_Product_Type_Api
  • Mage_Catalog_Model_Product_Type_Api_V2
  • Mage_Catalog_Model_Product_Type_Configurable
  • Mage_Catalog_Model_Product_Type_Configurable_Attribute
  • Mage_Catalog_Model_Product_Type_Configurable_Price
  • Mage_Catalog_Model_Product_Type_Grouped
  • Mage_Catalog_Model_Product_Type_Grouped_Price
  • Mage_Catalog_Model_Product_Type_Price
  • Mage_Catalog_Model_Product_Type_Simple
  • Mage_Catalog_Model_Product_Type_Virtual
  • Mage_Catalog_Model_Product_Url
  • Mage_Catalog_Model_Product_Visibility
  • Mage_Catalog_Model_Product_Website
  • Mage_Catalog_Model_Resource_Abstract
  • Mage_Catalog_Model_Resource_Attribute
  • Mage_Catalog_Model_Resource_Category
  • Mage_Catalog_Model_Resource_Category_Attribute_Collection
  • Mage_Catalog_Model_Resource_Category_Attribute_Frontend_Image
  • Mage_Catalog_Model_Resource_Category_Attribute_Source_Layout
  • Mage_Catalog_Model_Resource_Category_Attribute_Source_Mode
  • Mage_Catalog_Model_Resource_Category_Attribute_Source_Page
  • Mage_Catalog_Model_Resource_Category_Collection
  • Mage_Catalog_Model_Resource_Category_Flat
  • Mage_Catalog_Model_Resource_Category_Flat_Collection
  • Mage_Catalog_Model_Resource_Category_Indexer_Product
  • Mage_Catalog_Model_Resource_Category_Tree
  • Mage_Catalog_Model_Resource_Collection_Abstract
  • Mage_Catalog_Model_Resource_Config
  • Mage_Catalog_Model_Resource_Eav_Attribute
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Abstract
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Attribute
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Attribute_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Attribute_Frontend_Image
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Attribute_Source_Layout
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Attribute_Source_Mode
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Attribute_Source_Page
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Flat
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Flat_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Indexer_Product
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Tree
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Collection_Abstract
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Config
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Attribute
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Decimal
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Layer_Filter_Price
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Action
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Image
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Media
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Tierprice
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Backend_Urlkey
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Frontend_Image
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Attribute_Frontend_Tierprice
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Compare_Item
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Compare_Item_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Flat
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Flat_Indexer
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Abstract
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Eav
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Eav_Abstract
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Eav_Decimal
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Eav_Source
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Configurable
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Default
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Grouped
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Product_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option_Value
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option_Value_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Relation
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Status
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Type_Configurable
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Type_Configurable_Attribute
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Type_Configurable_Attribute_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Type_Configurable_Product_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Website
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Sendfriend
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Sendfriend_Collection
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Setup
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Url
  • Mage_Catalog_Model_Resource_Helper_Mysql4
  • Mage_Catalog_Model_Resource_Layer_Filter_Attribute
  • Mage_Catalog_Model_Resource_Layer_Filter_Decimal
  • Mage_Catalog_Model_Resource_Layer_Filter_Price
  • Mage_Catalog_Model_Resource_Product
  • Mage_Catalog_Model_Resource_Product_Action
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Groupprice
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Groupprice_Abstract
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Image
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Media
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Tierprice
  • Mage_Catalog_Model_Resource_Product_Attribute_Backend_Urlkey
  • Mage_Catalog_Model_Resource_Product_Attribute_Collection
  • Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Image
  • Mage_Catalog_Model_Resource_Product_Attribute_Frontend_Tierprice
  • Mage_Catalog_Model_Resource_Product_Collection
  • Mage_Catalog_Model_Resource_Product_Compare_Item
  • Mage_Catalog_Model_Resource_Product_Compare_Item_Collection
  • Mage_Catalog_Model_Resource_Product_Flat
  • Mage_Catalog_Model_Resource_Product_Flat_Indexer
  • Mage_Catalog_Model_Resource_Product_Indexer_Abstract
  • Mage_Catalog_Model_Resource_Product_Indexer_Eav
  • Mage_Catalog_Model_Resource_Product_Indexer_Eav_Abstract
  • Mage_Catalog_Model_Resource_Product_Indexer_Eav_Decimal
  • Mage_Catalog_Model_Resource_Product_Indexer_Eav_Source
  • Mage_Catalog_Model_Resource_Product_Indexer_Price
  • Mage_Catalog_Model_Resource_Product_Indexer_Price_Configurable
  • Mage_Catalog_Model_Resource_Product_Indexer_Price_Default
  • Mage_Catalog_Model_Resource_Product_Indexer_Price_Grouped
  • Mage_Catalog_Model_Resource_Product_Link
  • Mage_Catalog_Model_Resource_Product_Link_Collection
  • Mage_Catalog_Model_Resource_Product_Link_Product_Collection
  • Mage_Catalog_Model_Resource_Product_Option
  • Mage_Catalog_Model_Resource_Product_Option_Collection
  • Mage_Catalog_Model_Resource_Product_Option_Value
  • Mage_Catalog_Model_Resource_Product_Option_Value_Collection
  • Mage_Catalog_Model_Resource_Product_Relation
  • Mage_Catalog_Model_Resource_Product_Status
  • Mage_Catalog_Model_Resource_Product_Type_Configurable
  • Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute
  • Mage_Catalog_Model_Resource_Product_Type_Configurable_Attribute_Collection
  • Mage_Catalog_Model_Resource_Product_Type_Configurable_Product_Collection
  • Mage_Catalog_Model_Resource_Product_Website
  • Mage_Catalog_Model_Resource_Setup
  • Mage_Catalog_Model_Resource_Url
  • Mage_Catalog_Model_Session
  • Mage_Catalog_Model_System_Config_Backend_Catalog_Category_Flat
  • Mage_Catalog_Model_System_Config_Backend_Catalog_Product_Flat
  • Mage_Catalog_Model_System_Config_Backend_Catalog_Url_Rewrite_Suffix
  • Mage_Catalog_Model_Template_Filter
  • Mage_Catalog_Model_Url
  • Mage_Catalog_Product_CompareController
  • Mage_Catalog_ProductController
  • Mage_Catalog_Seo_SitemapController
  • Mage_CatalogSearch_Model_Resource_Helper_Mysql4
  • Mage_XmlConnect_Model_Catalog_Category_Media_Config

Interfaces

  • Mage_Catalog_Helper_Product_Configuration_Interface
  • Mage_Catalog_Model_Product_Condition_Interface
  • Mage_Catalog_Model_Product_Configuration_Item_Interface
  • Mage_Catalog_Model_Product_Configuration_Item_Option_Interface
  • Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Indexer_Price_Interface
  • Mage_Catalog_Model_Resource_Product_Indexer_Price_Interface
  • Overview
  • Package
  • Class
  • Tree
   1: <?php
   2: /**
   3:  * Magento
   4:  *
   5:  * NOTICE OF LICENSE
   6:  *
   7:  * This source file is subject to the Open Software License (OSL 3.0)
   8:  * that is bundled with this package in the file LICENSE.txt.
   9:  * It is also available through the world-wide-web at this URL:
  10:  * http://opensource.org/licenses/osl-3.0.php
  11:  * If you did not receive a copy of the license and are unable to
  12:  * obtain it through the world-wide-web, please send an email
  13:  * to license@magentocommerce.com so we can send you a copy immediately.
  14:  *
  15:  * DISCLAIMER
  16:  *
  17:  * Do not edit or add to this file if you wish to upgrade Magento to newer
  18:  * versions in the future. If you wish to customize Magento for your
  19:  * needs please refer to http://www.magentocommerce.com for more information.
  20:  *
  21:  * @category    Mage
  22:  * @package     Mage_Catalog
  23:  * @copyright   Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24:  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  25:  */
  26: 
  27: 
  28: /**
  29:  * Catalog url rewrite resource model
  30:  *
  31:  * @category    Mage
  32:  * @package     Mage_Catalog
  33:  * @author      Magento Core Team <core@magentocommerce.com>
  34:  */
  35: class Mage_Catalog_Model_Resource_Url extends Mage_Core_Model_Resource_Db_Abstract
  36: {
  37:     /**
  38:      * Stores configuration array
  39:      *
  40:      * @var array
  41:      */
  42:     protected $_stores;
  43: 
  44:     /**
  45:      * Category attribute properties cache
  46:      *
  47:      * @var array
  48:      */
  49:     protected $_categoryAttributes          = array();
  50: 
  51:     /**
  52:      * Product attribute properties cache
  53:      *
  54:      * @var array
  55:      */
  56:     protected $_productAttributes           = array();
  57: 
  58:     /**
  59:      * Limit products for select
  60:      *
  61:      * @var int
  62:      */
  63:     protected $_productLimit                = 250;
  64: 
  65:     /**
  66:      * Cache of root category children ids
  67:      *
  68:      * @var array
  69:      */
  70:     protected $_rootChildrenIds             = array();
  71: 
  72:     /**
  73:      * Load core Url rewrite model
  74:      *
  75:      */
  76:     protected function _construct()
  77:     {
  78:         $this->_init('core/url_rewrite', 'url_rewrite_id');
  79:     }
  80: 
  81:     /**
  82:      * Retrieve stores array or store model
  83:      *
  84:      * @param int $storeId
  85:      * @return Mage_Core_Model_Store|array
  86:      */
  87:     public function getStores($storeId = null)
  88:     {
  89:         if ($this->_stores === null) {
  90:             $this->_stores = $this->_prepareStoreRootCategories(Mage::app()->getStores());
  91:         }
  92:         if ($storeId && isset($this->_stores[$storeId])) {
  93:             return $this->_stores[$storeId];
  94:         }
  95:         return $this->_stores;
  96:     }
  97: 
  98:     /**
  99:      * Retrieve Category model singleton
 100:      *
 101:      * @return Mage_Catalog_Model_Category
 102:      */
 103:     public function getCategoryModel()
 104:     {
 105:         return Mage::getSingleton('catalog/category');
 106:     }
 107: 
 108:     /**
 109:      * Retrieve product model singleton
 110:      *
 111:      * @return Mage_Catalog_Model_Product
 112:      */
 113:     public function getProductModel()
 114:     {
 115:         return Mage::getSingleton('catalog/product');
 116:     }
 117: 
 118:     /**
 119:      * Retrieve rewrite by idPath
 120:      *
 121:      * @param string $idPath
 122:      * @param int $storeId
 123:      * @return Varien_Object|false
 124:      */
 125:     public function getRewriteByIdPath($idPath, $storeId)
 126:     {
 127:         $adapter = $this->_getReadAdapter();
 128:         $select = $adapter->select()
 129:             ->from($this->getMainTable())
 130:             ->where('store_id = :store_id')
 131:             ->where('id_path = :id_path');
 132:         $bind = array(
 133:             'store_id' => (int)$storeId,
 134:             'id_path'  => $idPath
 135:         );
 136:         $row = $adapter->fetchRow($select, $bind);
 137: 
 138:         if (!$row) {
 139:             return false;
 140:         }
 141:         $rewrite = new Varien_Object($row);
 142:         $rewrite->setIdFieldName($this->getIdFieldName());
 143: 
 144:         return $rewrite;
 145:     }
 146: 
 147:     /**
 148:      * Retrieve rewrite by requestPath
 149:      *
 150:      * @param string $requestPath
 151:      * @param int $storeId
 152:      * @return Varien_Object|false
 153:      */
 154:     public function getRewriteByRequestPath($requestPath, $storeId)
 155:     {
 156:         $adapter = $this->_getWriteAdapter();
 157:         $select = $adapter->select()
 158:             ->from($this->getMainTable())
 159:             ->where('store_id = :store_id')
 160:             ->where('request_path = :request_path');
 161:         $bind = array(
 162:             'request_path'  => $requestPath,
 163:             'store_id'      => (int)$storeId
 164:         );
 165:         $row = $adapter->fetchRow($select, $bind);
 166: 
 167:         if (!$row) {
 168:             return false;
 169:         }
 170:         $rewrite = new Varien_Object($row);
 171:         $rewrite->setIdFieldName($this->getIdFieldName());
 172: 
 173:         return $rewrite;
 174:     }
 175: 
 176:     /**
 177:      * Get last used increment part of rewrite request path
 178:      *
 179:      * @param string $prefix
 180:      * @param string $suffix
 181:      * @param int $storeId
 182:      * @return int
 183:      */
 184:     public function getLastUsedRewriteRequestIncrement($prefix, $suffix, $storeId)
 185:     {
 186:         $adapter = $this->_getWriteAdapter();
 187:         $requestPathField = new Zend_Db_Expr($adapter->quoteIdentifier('request_path'));
 188:         //select increment part of request path and cast expression to integer
 189:         $urlIncrementPartExpression = Mage::getResourceHelper('eav')
 190:             ->getCastToIntExpression($adapter->getSubstringSql(
 191:                 $requestPathField,
 192:                 strlen($prefix) + 1,
 193:                 $adapter->getLengthSql($requestPathField) . ' - ' . strlen($prefix) . ' - ' . strlen($suffix)
 194:             ));
 195:         $select = $adapter->select()
 196:             ->from($this->getMainTable(), new Zend_Db_Expr('MAX(' . $urlIncrementPartExpression . ')'))
 197:             ->where('store_id = :store_id')
 198:             ->where('request_path LIKE :request_path')
 199:             ->where($adapter->prepareSqlCondition('request_path', array(
 200:                 'regexp' => '^' . preg_quote($prefix) . '[0-9]*' . preg_quote($suffix) . '$'
 201:             )));
 202:         $bind = array(
 203:             'store_id'            => (int)$storeId,
 204:             'request_path'        => $prefix . '%' . $suffix,
 205:         );
 206: 
 207:         return (int)$adapter->fetchOne($select, $bind);
 208:     }
 209: 
 210:     /**
 211:      * Validate array of request paths. Return first not used path in case if validations passed
 212:      *
 213:      * @param array $paths
 214:      * @param int $storeId
 215:      * @return false | string
 216:      */
 217:     public function checkRequestPaths($paths, $storeId)
 218:     {
 219:         $adapter = $this->_getWriteAdapter();
 220:         $select = $adapter->select()
 221:             ->from($this->getMainTable(), 'request_path')
 222:             ->where('store_id = :store_id')
 223:             ->where('request_path IN (?)', $paths);
 224:         $data = $adapter->fetchCol($select, array('store_id' => $storeId));
 225:         $paths = array_diff($paths, $data);
 226:         if (empty($paths)) {
 227:             return false;
 228:         }
 229:         reset($paths);
 230: 
 231:         return current($paths);
 232:     }
 233: 
 234:     /**
 235:      * Prepare rewrites for condition
 236:      *
 237:      * @param int $storeId
 238:      * @param int|array $categoryIds
 239:      * @param int|array $productIds
 240:      * @return array
 241:      */
 242:     public function prepareRewrites($storeId, $categoryIds = null, $productIds = null)
 243:     {
 244:         $rewrites   = array();
 245:         $adapter    = $this->_getWriteAdapter();
 246:         $select     = $adapter->select()
 247:             ->from($this->getMainTable())
 248:             ->where('store_id = :store_id')
 249:             ->where('is_system = ?', 1);
 250:         $bind = array('store_id' => $storeId);
 251:         if ($categoryIds === null) {
 252:             $select->where('category_id IS NULL');
 253:         } elseif ($categoryIds) {
 254:             $catIds = is_array($categoryIds) ? $categoryIds : array($categoryIds);
 255: 
 256:             // Check maybe we request products and root category id is within categoryIds,
 257:             // it's a separate case because root category products are stored with NULL categoryId
 258:             if ($productIds) {
 259:                 $addNullCategory = in_array($this->getStores($storeId)->getRootCategoryId(), $catIds);
 260:             } else {
 261:                 $addNullCategory = false;
 262:             }
 263: 
 264:             // Compose optimal condition
 265:             if ($addNullCategory) {
 266:                 $select->where('category_id IN(?) OR category_id IS NULL', $catIds);
 267:             } else {
 268:                 $select->where('category_id IN(?)', $catIds);
 269:             }
 270:         }
 271: 
 272:         if ($productIds === null) {
 273:             $select->where('product_id IS NULL');
 274:         } elseif ($productIds) {
 275:             $select->where('product_id IN(?)', $productIds);
 276:         }
 277: 
 278:         $rowSet = $adapter->fetchAll($select, $bind);
 279: 
 280:         foreach ($rowSet as $row) {
 281:             $rewrite = new Varien_Object($row);
 282:             $rewrite->setIdFieldName($this->getIdFieldName());
 283:             $rewrites[$rewrite->getIdPath()] = $rewrite;
 284:         }
 285: 
 286:         return $rewrites;
 287:     }
 288: 
 289:     /**
 290:      * Save rewrite URL
 291:      *
 292:      * @param array $rewriteData
 293:      * @param int|Varien_Object $rewrite
 294:      * @return Mage_Catalog_Model_Resource_Url
 295:      */
 296:     public function saveRewrite($rewriteData, $rewrite)
 297:     {
 298:         $adapter = $this->_getWriteAdapter();
 299:         try {
 300:             $adapter->insertOnDuplicate($this->getMainTable(), $rewriteData);
 301:         } catch (Exception $e) {
 302:             Mage::logException($e);
 303:             Mage::throwException(Mage::helper('catalog')->__('An error occurred while saving the URL rewrite'));
 304:         }
 305: 
 306:         if ($rewrite && $rewrite->getId()) {
 307:             if ($rewriteData['request_path'] != $rewrite->getRequestPath()) {
 308:                 // Update existing rewrites history and avoid chain redirects
 309:                 $where = array('target_path = ?' => $rewrite->getRequestPath());
 310:                 if ($rewrite->getStoreId()) {
 311:                     $where['store_id = ?'] = (int)$rewrite->getStoreId();
 312:                 }
 313:                 $adapter->update(
 314:                     $this->getMainTable(),
 315:                     array('target_path' => $rewriteData['request_path']),
 316:                     $where
 317:                 );
 318:             }
 319:         }
 320:         unset($rewriteData);
 321: 
 322:         return $this;
 323:     }
 324: 
 325:     /**
 326:      * Saves rewrite history
 327:      *
 328:      * @param array $rewriteData
 329:      * @return Mage_Catalog_Model_Resource_Url
 330:      */
 331:     public function saveRewriteHistory($rewriteData)
 332:     {
 333:         $rewriteData = new Varien_Object($rewriteData);
 334:         // check if rewrite exists with save request_path
 335:         $rewrite = $this->getRewriteByRequestPath($rewriteData->getRequestPath(), $rewriteData->getStoreId());
 336:         if ($rewrite === false) {
 337:             // create permanent redirect
 338:             $this->_getWriteAdapter()->insert($this->getMainTable(), $rewriteData->getData());
 339:         }
 340: 
 341:         return $this;
 342:     }
 343: 
 344:     /**
 345:      * Save category attribute
 346:      *
 347:      * @param Varien_Object $category
 348:      * @param string $attributeCode
 349:      * @return Mage_Catalog_Model_Resource_Url
 350:      */
 351:     public function saveCategoryAttribute(Varien_Object $category, $attributeCode)
 352:     {
 353:         $adapter = $this->_getWriteAdapter();
 354:         if (!isset($this->_categoryAttributes[$attributeCode])) {
 355:             $attribute = $this->getCategoryModel()->getResource()->getAttribute($attributeCode);
 356: 
 357:             $this->_categoryAttributes[$attributeCode] = array(
 358:                 'entity_type_id' => $attribute->getEntityTypeId(),
 359:                 'attribute_id'   => $attribute->getId(),
 360:                 'table'          => $attribute->getBackend()->getTable(),
 361:                 'is_global'      => $attribute->getIsGlobal()
 362:             );
 363:             unset($attribute);
 364:         }
 365: 
 366:         $attributeTable = $this->_categoryAttributes[$attributeCode]['table'];
 367: 
 368:         $attributeData = array(
 369:             'entity_type_id'    => $this->_categoryAttributes[$attributeCode]['entity_type_id'],
 370:             'attribute_id'      => $this->_categoryAttributes[$attributeCode]['attribute_id'],
 371:             'store_id'          => $category->getStoreId(),
 372:             'entity_id'         => $category->getId(),
 373:             'value'             => $category->getData($attributeCode)
 374:         );
 375: 
 376:         if ($this->_categoryAttributes[$attributeCode]['is_global'] || $category->getStoreId() == 0) {
 377:             $attributeData['store_id'] = 0;
 378:         }
 379: 
 380:         $select = $adapter->select()
 381:             ->from($attributeTable)
 382:             ->where('entity_type_id = ?', (int)$attributeData['entity_type_id'])
 383:             ->where('attribute_id = ?', (int)$attributeData['attribute_id'])
 384:             ->where('store_id = ?', (int)$attributeData['store_id'])
 385:             ->where('entity_id = ?', (int)$attributeData['entity_id']);
 386: 
 387:         $row = $adapter->fetchRow($select);
 388:         $whereCond = array('value_id = ?' => $row['value_id']);
 389:         if ($row) {
 390:             $adapter->update($attributeTable, $attributeData, $whereCond);
 391:         } else {
 392:             $adapter->insert($attributeTable, $attributeData);
 393:         }
 394: 
 395:         if ($attributeData['store_id'] != 0) {
 396:             $attributeData['store_id'] = 0;
 397:             $select = $adapter->select()
 398:                 ->from($attributeTable)
 399:                 ->where('entity_type_id = ?', (int)$attributeData['entity_type_id'])
 400:                 ->where('attribute_id = ?', (int)$attributeData['attribute_id'])
 401:                 ->where('store_id = ?', (int)$attributeData['store_id'])
 402:                 ->where('entity_id = ?', (int)$attributeData['entity_id']);
 403: 
 404:             $row = $adapter->fetchRow($select);
 405:             if ($row) {
 406:                 $whereCond = array('value_id = ?' => $row['value_id']);
 407:                 $adapter->update($attributeTable, $attributeData, $whereCond);
 408:             } else {
 409:                 $adapter->insert($attributeTable, $attributeData);
 410:             }
 411:         }
 412:         unset($attributeData);
 413: 
 414:         return $this;
 415:     }
 416: 
 417:     /**
 418:      * Retrieve category attributes
 419:      *
 420:      * @param string $attributeCode
 421:      * @param int|array $categoryIds
 422:      * @param int $storeId
 423:      * @return array
 424:      */
 425:     protected function _getCategoryAttribute($attributeCode, $categoryIds, $storeId)
 426:     {
 427:         $adapter = $this->_getWriteAdapter();
 428:         if (!isset($this->_categoryAttributes[$attributeCode])) {
 429:             $attribute = $this->getCategoryModel()->getResource()->getAttribute($attributeCode);
 430: 
 431:             $this->_categoryAttributes[$attributeCode] = array(
 432:                 'entity_type_id' => $attribute->getEntityTypeId(),
 433:                 'attribute_id'   => $attribute->getId(),
 434:                 'table'          => $attribute->getBackend()->getTable(),
 435:                 'is_global'      => $attribute->getIsGlobal(),
 436:                 'is_static'      => $attribute->isStatic()
 437:             );
 438:             unset($attribute);
 439:         }
 440: 
 441:         if (!is_array($categoryIds)) {
 442:             $categoryIds = array($categoryIds);
 443:         }
 444: 
 445:         $attributeTable = $this->_categoryAttributes[$attributeCode]['table'];
 446:         $select         = $adapter->select();
 447:         $bind           = array();
 448:         if ($this->_categoryAttributes[$attributeCode]['is_static']) {
 449:             $select
 450:                 ->from(
 451:                     $this->getTable('catalog/category'),
 452:                     array('value' => $attributeCode, 'entity_id' => 'entity_id')
 453:                 )
 454:                 ->where('entity_id IN(?)', $categoryIds);
 455:         } elseif ($this->_categoryAttributes[$attributeCode]['is_global'] || $storeId == 0) {
 456:             $select
 457:                 ->from($attributeTable, array('entity_id', 'value'))
 458:                 ->where('attribute_id = :attribute_id')
 459:                 ->where('store_id = ?', 0)
 460:                 ->where('entity_id IN(?)', $categoryIds);
 461:             $bind['attribute_id'] = $this->_categoryAttributes[$attributeCode]['attribute_id'];
 462:         } else {
 463:             $valueExpr = $adapter->getCheckSql('t2.value_id > 0', 't2.value', 't1.value');
 464:             $select
 465:                 ->from(
 466:                     array('t1' => $attributeTable),
 467:                     array('entity_id', 'value' => $valueExpr)
 468:                 )
 469:                 ->joinLeft(
 470:                     array('t2' => $attributeTable),
 471:                     't1.entity_id = t2.entity_id AND t1.attribute_id = t2.attribute_id AND t2.store_id = :store_id',
 472:                     array()
 473:                 )
 474:                 ->where('t1.store_id = ?', 0)
 475:                 ->where('t1.attribute_id = :attribute_id')
 476:                 ->where('t1.entity_id IN(?)', $categoryIds);
 477: 
 478:             $bind['attribute_id'] = $this->_categoryAttributes[$attributeCode]['attribute_id'];
 479:             $bind['store_id']     = $storeId;
 480:         }
 481: 
 482:         $rowSet = $adapter->fetchAll($select, $bind);
 483: 
 484:         $attributes = array();
 485:         foreach ($rowSet as $row) {
 486:             $attributes[$row['entity_id']] = $row['value'];
 487:         }
 488:         unset($rowSet);
 489:         foreach ($categoryIds as $categoryId) {
 490:             if (!isset($attributes[$categoryId])) {
 491:                 $attributes[$categoryId] = null;
 492:             }
 493:         }
 494: 
 495:         return $attributes;
 496:     }
 497: 
 498:     /**
 499:      * Save product attribute
 500:      *
 501:      * @param Varien_Object $product
 502:      * @param string $attributeCode
 503:      * @return Mage_Catalog_Model_Resource_Url
 504:      */
 505:     public function saveProductAttribute(Varien_Object $product, $attributeCode)
 506:     {
 507:         $adapter = $this->_getWriteAdapter();
 508:         if (!isset($this->_productAttributes[$attributeCode])) {
 509:             $attribute = $this->getProductModel()->getResource()->getAttribute($attributeCode);
 510: 
 511:             $this->_productAttributes[$attributeCode] = array(
 512:                 'entity_type_id' => $attribute->getEntityTypeId(),
 513:                 'attribute_id'   => $attribute->getId(),
 514:                 'table'          => $attribute->getBackend()->getTable(),
 515:                 'is_global'      => $attribute->getIsGlobal()
 516:             );
 517:             unset($attribute);
 518:         }
 519: 
 520:         $attributeTable = $this->_productAttributes[$attributeCode]['table'];
 521: 
 522:         $attributeData = array(
 523:             'entity_type_id'    => $this->_productAttributes[$attributeCode]['entity_type_id'],
 524:             'attribute_id'      => $this->_productAttributes[$attributeCode]['attribute_id'],
 525:             'store_id'          => $product->getStoreId(),
 526:             'entity_id'         => $product->getId(),
 527:             'value'             => $product->getData($attributeCode)
 528:         );
 529: 
 530:         if ($this->_productAttributes[$attributeCode]['is_global'] || $product->getStoreId() == 0) {
 531:             $attributeData['store_id'] = 0;
 532:         }
 533: 
 534:         $select = $adapter->select()
 535:             ->from($attributeTable)
 536:             ->where('entity_type_id = ?', (int)$attributeData['entity_type_id'])
 537:             ->where('attribute_id = ?', (int)$attributeData['attribute_id'])
 538:             ->where('store_id = ?', (int)$attributeData['store_id'])
 539:             ->where('entity_id = ?', (int)$attributeData['entity_id']);
 540: 
 541:         $row = $adapter->fetchRow($select);
 542:         if ($row) {
 543:             $whereCond = array('value_id = ?' => $row['value_id']);
 544:             $adapter->update($attributeTable, $attributeData, $whereCond);
 545:         } else {
 546:             $adapter->insert($attributeTable, $attributeData);
 547:         }
 548: 
 549:         if ($attributeData['store_id'] != 0) {
 550:             $attributeData['store_id'] = 0;
 551:             $select = $adapter->select()
 552:                 ->from($attributeTable)
 553:                 ->where('entity_type_id = ?', (int)$attributeData['entity_type_id'])
 554:                 ->where('attribute_id = ?', (int)$attributeData['attribute_id'])
 555:                 ->where('store_id = ?', (int)$attributeData['store_id'])
 556:                 ->where('entity_id = ?', (int)$attributeData['entity_id']);
 557: 
 558:             $row = $adapter->fetchRow($select);
 559:             if ($row) {
 560:                 $whereCond = array('value_id = ?' => $row['value_id']);
 561:                 $adapter->update($attributeTable, $attributeData, $whereCond);
 562:             } else {
 563:                 $adapter->insert($attributeTable, $attributeData);
 564:             }
 565:         }
 566:         unset($attributeData);
 567: 
 568:         return $this;
 569:     }
 570: 
 571:     /**
 572:      * Retrieve product attribute
 573:      *
 574:      * @param string $attributeCode
 575:      * @param int|array $productIds
 576:      * @param string $storeId
 577:      * @return array
 578:      */
 579:     public function _getProductAttribute($attributeCode, $productIds, $storeId)
 580:     {
 581:         $adapter = $this->_getReadAdapter();
 582:         if (!isset($this->_productAttributes[$attributeCode])) {
 583:             $attribute = $this->getProductModel()->getResource()->getAttribute($attributeCode);
 584: 
 585:             $this->_productAttributes[$attributeCode] = array(
 586:                 'entity_type_id' => $attribute->getEntityTypeId(),
 587:                 'attribute_id'   => $attribute->getId(),
 588:                 'table'          => $attribute->getBackend()->getTable(),
 589:                 'is_global'      => $attribute->getIsGlobal()
 590:             );
 591:             unset($attribute);
 592:         }
 593: 
 594:         if (!is_array($productIds)) {
 595:             $productIds = array($productIds);
 596:         }
 597:         $bind = array('attribute_id' => $this->_productAttributes[$attributeCode]['attribute_id']);
 598:         $select = $adapter->select();
 599:         $attributeTable = $this->_productAttributes[$attributeCode]['table'];
 600:         if ($this->_productAttributes[$attributeCode]['is_global'] || $storeId == 0) {
 601:             $select
 602:                 ->from($attributeTable, array('entity_id', 'value'))
 603:                 ->where('attribute_id = :attribute_id')
 604:                 ->where('store_id = ?', 0)
 605:                 ->where('entity_id IN(?)', $productIds);
 606:         } else {
 607:             $valueExpr = $adapter->getCheckSql('t2.value_id > 0', 't2.value', 't1.value');
 608:             $select
 609:                 ->from(
 610:                     array('t1' => $attributeTable),
 611:                     array('entity_id', 'value' => $valueExpr)
 612:                 )
 613:                 ->joinLeft(
 614:                     array('t2' => $attributeTable),
 615:                     't1.entity_id = t2.entity_id AND t1.attribute_id = t2.attribute_id AND t2.store_id=:store_id',
 616:                     array()
 617:                 )
 618:                 ->where('t1.store_id = ?', 0)
 619:                 ->where('t1.attribute_id = :attribute_id')
 620:                 ->where('t1.entity_id IN(?)', $productIds);
 621:             $bind['store_id'] = $storeId;
 622:         }
 623: 
 624:         $rowSet = $adapter->fetchAll($select, $bind);
 625: 
 626:         $attributes = array();
 627:         foreach ($rowSet as $row) {
 628:             $attributes[$row['entity_id']] = $row['value'];
 629:         }
 630:         unset($rowSet);
 631:         foreach ($productIds as $productIds) {
 632:             if (!isset($attributes[$productIds])) {
 633:                 $attributes[$productIds] = null;
 634:             }
 635:         }
 636: 
 637:         return $attributes;
 638:     }
 639: 
 640:     /**
 641:      * Prepare category parentId
 642:      *
 643:      * @param Varien_Object $category
 644:      * @return Mage_Catalog_Model_Resource_Url
 645:      */
 646:     protected function _prepareCategoryParentId(Varien_Object $category)
 647:     {
 648:         if ($category->getPath() != $category->getId()) {
 649:             $split = explode('/', $category->getPath());
 650:             $category->setParentId($split[(count($split) - 2)]);
 651:         } else {
 652:             $category->setParentId(0);
 653:         }
 654:         return $this;
 655:     }
 656: 
 657:     /**
 658:      * Prepare stores root categories
 659:      *
 660:      * @param array $stores
 661:      * @return array
 662:      */
 663:     protected function _prepareStoreRootCategories($stores)
 664:     {
 665:         $rootCategoryIds = array();
 666:         foreach ($stores as $store) {
 667:             /* @var $store Mage_Core_Model_Store */
 668:             $rootCategoryIds[$store->getRootCategoryId()] = $store->getRootCategoryId();
 669:         }
 670:         if ($rootCategoryIds) {
 671:             $categories = $this->_getCategories($rootCategoryIds);
 672:         }
 673:         foreach ($stores as $store) {
 674:             /* @var $store Mage_Core_Model_Store */
 675:             $rootCategoryId = $store->getRootCategoryId();
 676:             if (isset($categories[$rootCategoryId])) {
 677:                 $store->setRootCategoryPath($categories[$rootCategoryId]->getPath());
 678:                 $store->setRootCategory($categories[$rootCategoryId]);
 679:             } else {
 680:                 unset($stores[$store->getId()]);
 681:             }
 682:         }
 683:         return $stores;
 684:     }
 685: 
 686:     /**
 687:      * Retrieve categories objects
 688:      * Either $categoryIds or $path (with ending slash) must be specified
 689:      *
 690:      * @param int|array $categoryIds
 691:      * @param int $storeId
 692:      * @param string $path
 693:      * @return array
 694:      */
 695:     protected function _getCategories($categoryIds, $storeId = null, $path = null)
 696:     {
 697:         $isActiveAttribute = Mage::getSingleton('eav/config')
 698:             ->getAttribute(Mage_Catalog_Model_Category::ENTITY, 'is_active');
 699:         $categories        = array();
 700:         $adapter           = $this->_getReadAdapter();
 701: 
 702:         if (!is_array($categoryIds)) {
 703:             $categoryIds = array($categoryIds);
 704:         }
 705:         $isActiveExpr = $adapter->getCheckSql('c.value_id > 0', 'c.value', 'c.value');
 706:         $select = $adapter->select()
 707:             ->from(array('main_table' => $this->getTable('catalog/category')), array(
 708:                 'main_table.entity_id',
 709:                 'main_table.parent_id',
 710:                 'main_table.level',
 711:                 'is_active' => $isActiveExpr,
 712:                 'main_table.path'));
 713: 
 714:         // Prepare variables for checking whether categories belong to store
 715:         if ($path === null) {
 716:             $select->where('main_table.entity_id IN(?)', $categoryIds);
 717:         } else {
 718:             // Ensure that path ends with '/', otherwise we can get wrong results - e.g. $path = '1/2' will get '1/20'
 719:             if (substr($path, -1) != '/') {
 720:                 $path .= '/';
 721:             }
 722: 
 723:             $select
 724:                 ->where('main_table.path LIKE ?', $path . '%')
 725:                 ->order('main_table.path');
 726:         }
 727:         $table = $this->getTable(array('catalog/category', 'int'));
 728:         $select->joinLeft(array('d' => $table),
 729:             'd.attribute_id = :attribute_id AND d.store_id = 0 AND d.entity_id = main_table.entity_id',
 730:             array()
 731:         )
 732:         ->joinLeft(array('c' => $table),
 733:             'c.attribute_id = :attribute_id AND c.store_id = :store_id AND c.entity_id = main_table.entity_id',
 734:             array()
 735:         );
 736: 
 737:         if ($storeId !== null) {
 738:             $rootCategoryPath = $this->getStores($storeId)->getRootCategoryPath();
 739:             $rootCategoryPathLength = strlen($rootCategoryPath);
 740:         }
 741:         $bind = array(
 742:             'attribute_id' => (int)$isActiveAttribute->getId(),
 743:             'store_id'     => (int)$storeId
 744:         );
 745: 
 746:         $rowSet = $adapter->fetchAll($select, $bind);
 747:         foreach ($rowSet as $row) {
 748:             if ($storeId !== null) {
 749:                 // Check the category to be either store's root or its descendant
 750:                 // First - check that category's start is the same as root category
 751:                 if (substr($row['path'], 0, $rootCategoryPathLength) != $rootCategoryPath) {
 752:                     continue;
 753:                 }
 754:                 // Second - check non-root category - that it's really a descendant, not a simple string match
 755:                 if ((strlen($row['path']) > $rootCategoryPathLength)
 756:                     && ($row['path'][$rootCategoryPathLength] != '/')) {
 757:                     continue;
 758:                 }
 759:             }
 760: 
 761:             $category = new Varien_Object($row);
 762:             $category->setIdFieldName('entity_id');
 763:             $category->setStoreId($storeId);
 764:             $this->_prepareCategoryParentId($category);
 765: 
 766:             $categories[$category->getId()] = $category;
 767:         }
 768:         unset($rowSet);
 769: 
 770:         if ($storeId !== null && $categories) {
 771:             foreach (array('name', 'url_key', 'url_path') as $attributeCode) {
 772:                 $attributes = $this->_getCategoryAttribute($attributeCode, array_keys($categories),
 773:                     $category->getStoreId());
 774:                 foreach ($attributes as $categoryId => $attributeValue) {
 775:                     $categories[$categoryId]->setData($attributeCode, $attributeValue);
 776:                 }
 777:             }
 778:         }
 779: 
 780:         return $categories;
 781:     }
 782: 
 783:     /**
 784:      * Retrieve category data object
 785:      *
 786:      * @param int $categoryId
 787:      * @param int $storeId
 788:      * @return Varien_Object
 789:      */
 790:     public function getCategory($categoryId, $storeId)
 791:     {
 792:         if (!$categoryId || !$storeId) {
 793:             return false;
 794:         }
 795: 
 796:         $categories = $this->_getCategories($categoryId, $storeId);
 797:         if (isset($categories[$categoryId])) {
 798:             return $categories[$categoryId];
 799:         }
 800:         return false;
 801:     }
 802: 
 803:     /**
 804:      * Retrieve categories data objects by their ids. Return only categories that belong to specified store.
 805:      *
 806:      * @param int|array $categoryIds
 807:      * @param int $storeId
 808:      * @return array
 809:      */
 810:     public function getCategories($categoryIds, $storeId)
 811:     {
 812:         if (!$categoryIds || !$storeId) {
 813:             return false;
 814:         }
 815: 
 816:         return $this->_getCategories($categoryIds, $storeId);
 817:     }
 818: 
 819:     /**
 820:      * Retrieve category childs data objects
 821:      *
 822:      * @param Varien_Object $category
 823:      * @return Varien_Object
 824:      */
 825:     public function loadCategoryChilds(Varien_Object $category)
 826:     {
 827:         if ($category->getId() === null || $category->getStoreId() === null) {
 828:             return $category;
 829:         }
 830: 
 831:         $categories = $this->_getCategories(null, $category->getStoreId(), $category->getPath() . '/');
 832:         $category->setChilds(array());
 833:         foreach ($categories as $child) {
 834:             if (!is_array($child->getChilds())) {
 835:                 $child->setChilds(array());
 836:             }
 837:             if ($child->getParentId() == $category->getId()) {
 838:                 $category->setChilds($category->getChilds() + array($child->getId() => $child));
 839:             } else {
 840:                 if (isset($categories[$child->getParentId()])) {
 841:                     if (!is_array($categories[$child->getParentId()]->getChilds())) {
 842:                         $categories[$child->getParentId()]->setChilds(array());
 843:                     }
 844:                     $categories[$child->getParentId()]->setChilds(
 845:                         $categories[$child->getParentId()]->getChilds() + array($child->getId() => $child)
 846:                     );
 847:                 }
 848:             }
 849:         }
 850:         $category->setAllChilds($categories);
 851: 
 852:         return $category;
 853:     }
 854: 
 855:     /**
 856:      * Retrieves all children ids of root category tree
 857:      * Actually this routine can be used to get children ids of any category, not only root.
 858:      * But as far as result is cached in memory, it's not recommended to do so.
 859:      *
 860:      * @param Varien_Object $category
 861:      * @return Varien_Object
 862:      */
 863:     public function getRootChildrenIds($categoryId, $categoryPath, $includeStart = true)
 864:     {
 865:         if (!isset($this->_rootChildrenIds[$categoryId])) {
 866:             // Select all descedant category ids
 867:             $adapter = $this->_getReadAdapter();
 868:             $select = $adapter->select()
 869:                 ->from(array($this->getTable('catalog/category')), array('entity_id'))
 870:                 ->where('path LIKE ?', $categoryPath . '/%');
 871: 
 872:             $categoryIds = array();
 873:             $rowSet = $adapter->fetchAll($select);
 874:             foreach ($rowSet as $row) {
 875:                 $categoryIds[$row['entity_id']] = $row['entity_id'];
 876:             }
 877:             $this->_rootChildrenIds[$categoryId] = $categoryIds;
 878:         }
 879: 
 880:         $categoryIds = $this->_rootChildrenIds[$categoryId];
 881:         if ($includeStart) {
 882:             $categoryIds[$categoryId] = $categoryId;
 883:         }
 884:         return $categoryIds;
 885:     }
 886: 
 887:     /**
 888:      * Retrieve category parent path
 889:      *
 890:      * @param Varien_Object $category
 891:      * @return string
 892:      */
 893:     public function getCategoryParentPath(Varien_Object $category)
 894:     {
 895:         $store = Mage::app()->getStore($category->getStoreId());
 896: 
 897:         if ($category->getId() == $store->getRootCategoryId()) {
 898:             return '';
 899:         } elseif ($category->getParentId() == 1 || $category->getParentId() == $store->getRootCategoryId()) {
 900:             return '';
 901:         }
 902: 
 903:         $parentCategory = $this->getCategory($category->getParentId(), $store->getId());
 904:         return $parentCategory->getUrlPath() . '/';
 905:     }
 906: 
 907:     /**
 908:      * Retrieve product ids by category
 909:      *
 910:      * @param Varien_Object|int $category
 911:      * @return array
 912:      */
 913:     public function getProductIdsByCategory($category)
 914:     {
 915:         if ($category instanceof Varien_Object) {
 916:             $categoryId = $category->getId();
 917:         } else {
 918:             $categoryId = $category;
 919:         }
 920:         $adapter = $this->_getReadAdapter();
 921:         $select = $adapter->select()
 922:             ->from($this->getTable('catalog/category_product'), array('product_id'))
 923:             ->where('category_id = :category_id')
 924:             ->order('product_id');
 925:         $bind = array('category_id' => $categoryId);
 926: 
 927:         return $adapter->fetchCol($select, $bind);
 928:     }
 929: 
 930:     /**
 931:      * Retrieve Product data objects
 932:      *
 933:      * @param int|array $productIds
 934:      * @param int $storeId
 935:      * @param int $entityId
 936:      * @param int $lastEntityId
 937:      * @return array
 938:      */
 939:     protected function _getProducts($productIds, $storeId, $entityId, &$lastEntityId)
 940:     {
 941:         $products   = array();
 942:         $websiteId  = Mage::app()->getStore($storeId)->getWebsiteId();
 943:         $adapter    = $this->_getReadAdapter();
 944:         if ($productIds !== null) {
 945:             if (!is_array($productIds)) {
 946:                 $productIds = array($productIds);
 947:             }
 948:         }
 949:         $bind = array(
 950:             'website_id' => (int)$websiteId,
 951:             'entity_id'  => (int)$entityId,
 952:         );
 953:         $select = $adapter->select()
 954:             ->useStraightJoin(true)
 955:             ->from(array('e' => $this->getTable('catalog/product')), array('entity_id'))
 956:             ->join(
 957:                 array('w' => $this->getTable('catalog/product_website')),
 958:                 'e.entity_id = w.product_id AND w.website_id = :website_id',
 959:                 array()
 960:             )
 961:             ->where('e.entity_id > :entity_id')
 962:             ->order('e.entity_id')
 963:             ->limit($this->_productLimit);
 964:         if ($productIds !== null) {
 965:             $select->where('e.entity_id IN(?)', $productIds);
 966:         }
 967: 
 968:         $rowSet = $adapter->fetchAll($select, $bind);
 969:         foreach ($rowSet as $row) {
 970:             $product = new Varien_Object($row);
 971:             $product->setIdFieldName('entity_id');
 972:             $product->setCategoryIds(array());
 973:             $product->setStoreId($storeId);
 974:             $products[$product->getId()] = $product;
 975:             $lastEntityId = $product->getId();
 976:         }
 977: 
 978:         unset($rowSet);
 979: 
 980:         if ($products) {
 981:             $select = $adapter->select()
 982:                 ->from(
 983:                     $this->getTable('catalog/category_product'),
 984:                     array('product_id', 'category_id')
 985:                 )
 986:                 ->where('product_id IN(?)', array_keys($products));
 987:             $categories = $adapter->fetchAll($select);
 988:             foreach ($categories as $category) {
 989:                 $productId = $category['product_id'];
 990:                 $categoryIds = $products[$productId]->getCategoryIds();
 991:                 $categoryIds[] = $category['category_id'];
 992:                 $products[$productId]->setCategoryIds($categoryIds);
 993:             }
 994: 
 995:             foreach (array('name', 'url_key', 'url_path') as $attributeCode) {
 996:                 $attributes = $this->_getProductAttribute($attributeCode, array_keys($products), $storeId);
 997:                 foreach ($attributes as $productId => $attributeValue) {
 998:                     $products[$productId]->setData($attributeCode, $attributeValue);
 999:                 }
1000:             }
1001:         }
1002: 
1003:         return $products;
1004:     }
1005: 
1006:     /**
1007:      * Retrieve Product data object
1008:      *
1009:      * @param int $productId
1010:      * @param int $storeId
1011:      * @return Varien_Object
1012:      */
1013:     public function getProduct($productId, $storeId)
1014:     {
1015:         $entityId = 0;
1016:         $products = $this->_getProducts($productId, $storeId, 0, $entityId);
1017:         if (isset($products[$productId])) {
1018:             return $products[$productId];
1019:         }
1020:         return false;
1021:     }
1022: 
1023:     /**
1024:      * Retrieve Product data obects for store
1025:      *
1026:      * @param int $storeId
1027:      * @param int $lastEntityId
1028:      * @return array
1029:      */
1030:     public function getProductsByStore($storeId, &$lastEntityId)
1031:     {
1032:         return $this->_getProducts(null, $storeId, $lastEntityId, $lastEntityId);
1033:     }
1034: 
1035:     /**
1036:      * Retrieve Product data objects in category
1037:      *
1038:      * @param Varien_Object $category
1039:      * @param int $lastEntityId
1040:      * @return array
1041:      */
1042:     public function getProductsByCategory(Varien_Object $category, &$lastEntityId)
1043:     {
1044:         $productIds = $this->getProductIdsByCategory($category);
1045:         if (!$productIds) {
1046:             return array();
1047:         }
1048:         return $this->_getProducts($productIds, $category->getStoreId(), $lastEntityId, $lastEntityId);
1049:     }
1050: 
1051:     /**
1052:      * Find and remove unused products rewrites - a case when products were moved away from the category
1053:      * (either to other category or deleted), so rewrite "category_id-product_id" is invalid
1054:      *
1055:      * @param int $storeId
1056:      * @return Mage_Catalog_Model_Resource_Url
1057:      */
1058:     public function clearCategoryProduct($storeId)
1059:     {
1060:         $adapter = $this->_getWriteAdapter();
1061:         $select = $adapter->select()
1062:             ->from(array('tur' => $this->getMainTable()), $this->getIdFieldName())
1063:             ->joinLeft(
1064:                 array('tcp' => $this->getTable('catalog/category_product')),
1065:                 'tur.category_id = tcp.category_id AND tur.product_id = tcp.product_id',
1066:                 array()
1067:             )
1068:             ->where('tur.store_id = :store_id')
1069:             ->where('tur.category_id IS NOT NULL')
1070:             ->where('tur.product_id IS NOT NULL')
1071:             ->where('tcp.category_id IS NULL');
1072:         $rewriteIds = $adapter->fetchCol($select, array('store_id' => $storeId));
1073:         if ($rewriteIds) {
1074:             $where = array($this->getIdFieldName() . ' IN(?)' => $rewriteIds);
1075:             $adapter->delete($this->getMainTable(), $where);
1076:         }
1077: 
1078:         return $this;
1079:     }
1080: 
1081:     /**
1082:      * Remove unused rewrites for product - called after we created all needed rewrites for product and know the categories
1083:      * where the product is contained ($excludeCategoryIds), so we can remove all invalid product rewrites that have other category ids
1084:      *
1085:      * Notice: this routine is not identical to clearCategoryProduct(), because after checking all categories this one removes rewrites
1086:      * for product still contained within categories.
1087:      *
1088:      * @param int $productId Product entity Id
1089:      * @param int $storeId Store Id for rewrites
1090:      * @param array $excludeCategoryIds Array of category Ids that should be skipped
1091:      * @return Mage_Catalog_Model_Resource_Url
1092:      */
1093:     public function clearProductRewrites($productId, $storeId, $excludeCategoryIds = array())
1094:     {
1095:         $where = array(
1096:             'product_id = ?' => $productId,
1097:             'store_id = ?' => $storeId
1098:         );
1099: 
1100:         if (!empty($excludeCategoryIds)) {
1101:             $where['category_id NOT IN (?)'] = $excludeCategoryIds;
1102:             // If there's at least one category to skip, also skip root category, because product belongs to website
1103:             $where[] = 'category_id IS NOT NULL';
1104:         }
1105: 
1106:         $this->_getWriteAdapter()->delete($this->getMainTable(), $where);
1107: 
1108:         return $this;
1109:     }
1110: 
1111:     /**
1112:      * Finds and deletes all old category and category/product rewrites for store
1113:      * left from the times when categories/products belonged to store
1114:      *
1115:      * @param int $storeId
1116:      * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url
1117:      */
1118:     public function clearStoreCategoriesInvalidRewrites($storeId)
1119:     {
1120:         // Form a list of all current store categories ids
1121:         $store          = $this->getStores($storeId);
1122:         $rootCategoryId = $store->getRootCategoryId();
1123:         if (!$rootCategoryId) {
1124:             return $this;
1125:         }
1126:         $categoryIds = $this->getRootChildrenIds($rootCategoryId, $store->getRootCategoryPath());
1127: 
1128:         // Remove all store catalog rewrites that are for some category or cartegory/product not within store categories
1129:         $where   = array(
1130:             'store_id = ?' => $storeId,
1131:             'category_id IS NOT NULL', // For sure check that it's a catalog rewrite
1132:             'category_id NOT IN (?)' => $categoryIds
1133:         );
1134: 
1135:         $this->_getWriteAdapter()->delete($this->getMainTable(), $where);
1136: 
1137:         return $this;
1138:     }
1139: 
1140:     /**
1141:      * Finds and deletes product rewrites (that are not assigned to any category) for store
1142:      * left from the times when product was assigned to this store's website and now is not assigned
1143:      *
1144:      * Notice: this routine is different from clearProductRewrites() and clearCategoryProduct() because
1145:      * it handles direct rewrites to product without defined category (category_id IS NULL) whilst that routines
1146:      * handle only product rewrites within categories
1147:      *
1148:      * @param int $storeId
1149:      * @param int|array|null $productId
1150:      * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url
1151:      */
1152:     public function clearStoreProductsInvalidRewrites($storeId, $productId = null)
1153:     {
1154:         $store   = $this->getStores($storeId);
1155:         $adapter = $this->_getReadAdapter();
1156:         $bind    = array(
1157:             'website_id' => (int)$store->getWebsiteId(),
1158:             'store_id'   => (int)$storeId
1159:         );
1160:         $select = $adapter->select()
1161:             ->from(array('rewrite' => $this->getMainTable()), $this->getIdFieldName())
1162:             ->joinLeft(
1163:                 array('website' => $this->getTable('catalog/product_website')),
1164:                 'rewrite.product_id = website.product_id AND website.website_id = :website_id',
1165:                 array()
1166:             )->where('rewrite.store_id = :store_id')
1167:             ->where('rewrite.category_id IS NULL');
1168:         if ($productId) {
1169:             $select->where('rewrite.product_id IN (?)', $productId);
1170:         } else {
1171:             $select->where('rewrite.product_id IS NOT NULL');
1172:         }
1173:         $select->where('website.website_id IS NULL');
1174: 
1175:         $rewriteIds = $adapter->fetchCol($select, $bind);
1176:         if ($rewriteIds) {
1177:             $where = array($this->getIdFieldName() . ' IN(?)' => $rewriteIds);
1178:             $this->_getWriteAdapter()->delete($this->getMainTable(), $where);
1179:         }
1180: 
1181:         return $this;
1182:     }
1183: 
1184:     /**
1185:      * Finds and deletes old rewrites for store
1186:      * a) category rewrites left from the times when store had some other root category
1187:      * b) product rewrites left from products that once belonged to this site, but then deleted or just removed from website
1188:      *
1189:      * @param int $storeId
1190:      * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url
1191:      */
1192:     public function clearStoreInvalidRewrites($storeId)
1193:     {
1194:         $this->clearStoreCategoriesInvalidRewrites($storeId);
1195:         $this->clearStoreProductsInvalidRewrites($storeId);
1196:         return $this;
1197:     }
1198: 
1199:     /**
1200:      * Delete rewrites for associated to category products
1201:      *
1202:      * @param int $categoryId
1203:      * @param array $productIds
1204:      * @return Mage_Catalog_Model_Resource_Url
1205:      */
1206:     public function deleteCategoryProductRewrites($categoryId, $productIds)
1207:     {
1208:         $this->deleteCategoryProductStoreRewrites($categoryId, $productIds);
1209:         return $this;
1210:     }
1211: 
1212:     /**
1213:      * Delete URL rewrites for category products of specific store
1214:      *
1215:      * @param int $categoryId
1216:      * @param array|int|null $productIds
1217:      * @param null|int $storeId
1218:      * @return Mage_Catalog_Model_Resource_Url
1219:      */
1220:     public function deleteCategoryProductStoreRewrites($categoryId, $productIds = null, $storeId = null)
1221:     {
1222:         // Notice that we don't include category_id = NULL in case of root category,
1223:         // because product removed from all categories but assigned to store's website is still
1224:         // assumed to be in root cat. Unassigned products must be removed by other routine.
1225:         $condition = array('category_id = ?' => $categoryId);
1226:         if (empty($productIds)) {
1227:             $condition[] = 'product_id IS NOT NULL';
1228:         } else {
1229:             $condition['product_id IN (?)'] = $productIds;
1230:         }
1231: 
1232:         if ($storeId !== null) {
1233:             $condition['store_id IN(?)'] = $storeId;
1234:         }
1235: 
1236:         $this->_getWriteAdapter()->delete($this->getMainTable(), $condition);
1237:         return $this;
1238:     }
1239: 
1240:     /**
1241:      * Retrieve rewrites and visibility by store
1242:      * Input array format:
1243:      * product_id as key and store_id as value
1244:      * Output array format (product_id as key)
1245:      * store_id     int; store id
1246:      * visibility   int; visibility for store
1247:      * url_rewrite  string; rewrite URL for store
1248:      *
1249:      * @param array $products
1250:      * @return array
1251:      */
1252:     public function getRewriteByProductStore(array $products)
1253:     {
1254:         $result = array();
1255: 
1256:         if (empty($products)) {
1257:             return $result;
1258:         }
1259:         $adapter = $this->_getReadAdapter();
1260: 
1261:         $select = $adapter->select()
1262:             ->from(
1263:                 array('i' => $this->getTable('catalog/category_product_index')),
1264:                 array('product_id', 'store_id', 'visibility')
1265:             )
1266:             ->joinLeft(
1267:                 array('r' => $this->getMainTable()),
1268:                 'i.product_id = r.product_id AND i.store_id=r.store_id AND r.category_id IS NULL',
1269:                 array('request_path')
1270:             );
1271: 
1272:         $bind = array();
1273:         foreach ($products as $productId => $storeId) {
1274:             $catId = Mage::app()->getStore($storeId)->getRootCategoryId();
1275:             $productBind = 'product_id' . $productId;
1276:             $storeBind   = 'store_id' . $storeId;
1277:             $catBind     = 'category_id' . $catId;
1278:             $cond  = '(' . implode(' AND ', array(
1279:                 'i.product_id = :' . $productBind,
1280:                 'i.store_id = :' . $storeBind,
1281:                 'i.category_id = :' . $catBind,
1282:             )) . ')';
1283:             $bind[$productBind] = $productId;
1284:             $bind[$storeBind]   = $storeId;
1285:             $bind[$catBind]     = $catId;
1286:             $select->orWhere($cond);
1287:         }
1288: 
1289:         $rowSet = $adapter->fetchAll($select, $bind);
1290:         foreach ($rowSet as $row) {
1291:             $result[$row['product_id']] = array(
1292:                 'store_id'      => $row['store_id'],
1293:                 'visibility'    => $row['visibility'],
1294:                 'url_rewrite'   => $row['request_path'],
1295:             );
1296:         }
1297: 
1298:         return $result;
1299:     }
1300: 
1301:     /**
1302:      * Find and return final id path by request path
1303:      * Needed for permanent redirect old URLs.
1304:      *
1305:      * @param string $requestPath
1306:      * @param int $storeId
1307:      * @param array $_checkedPaths internal varible to prevent infinite loops.
1308:      * @return string | bool
1309:      */
1310:     public function findFinalTargetPath($requestPath, $storeId, &$_checkedPaths = array())
1311:     {
1312:         if (in_array($requestPath, $_checkedPaths)) {
1313:             return false;
1314:         }
1315: 
1316:         $_checkedPaths[] = $requestPath;
1317: 
1318:         $select = $this->_getWriteAdapter()->select()
1319:             ->from($this->getMainTable(), array('target_path', 'id_path'))
1320:             ->where('store_id = ?', $storeId)
1321:             ->where('request_path = ?', $requestPath);
1322: 
1323:         if ($row = $this->_getWriteAdapter()->fetchRow($select)) {
1324:             $idPath = $this->findFinalTargetPath($row['target_path'], $storeId, $_checkedPaths);
1325:             if (!$idPath) {
1326:                 return $row['id_path'];
1327:             } else {
1328:                 return $idPath;
1329:             }
1330:         }
1331: 
1332:         return false;
1333:     }
1334: 
1335:     /**
1336:      * Delete rewrite path record from the database.
1337:      *
1338:      * @param string $requestPath
1339:      * @param int $storeId
1340:      * @return void
1341:      */
1342:     public function deleteRewrite($requestPath, $storeId)
1343:     {
1344:         $this->deleteRewriteRecord($requestPath, $storeId);
1345:     }
1346: 
1347:     /**
1348:      * Delete rewrite path record from the database with RP checking.
1349:      *
1350:      * @param string $requestPath
1351:      * @param int $storeId
1352:      * @param bool $rp whether check rewrite option to be "Redirect = Permanent"
1353:      * @return void
1354:      */
1355:     public function deleteRewriteRecord($requestPath, $storeId, $rp = false)
1356:     {
1357:         $conditions =  array(
1358:             'store_id = ?' => $storeId,
1359:             'request_path = ?' => $requestPath,
1360:         );
1361:         if ($rp) {
1362:             $conditions['options = ?'] = 'RP';
1363:         }
1364:         $this->_getWriteAdapter()->delete($this->getMainTable(), $conditions);
1365:     }
1366: }
1367: 
Magento 1.7.0.2 API documentation generated by ApiGen 2.8.0