/app/code/core/Mage/Catalog/Model/Product.php
PHP | 1843 lines | 995 code | 180 blank | 668 comment | 83 complexity | 3277f92c61186a3ac36e7b69c3d509f0 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
- <?php
- /**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @category Mage
- * @package Mage_Catalog
- * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
- * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
- */
- /**
- * Catalog product model
- *
- * @category Mage
- * @package Mage_Catalog
- * @author Magento Core Team <core@magentocommerce.com>
- */
- class Mage_Catalog_Model_Product extends Mage_Catalog_Model_Abstract
- {
- /**
- * Entity code.
- * Can be used as part of method name for entity processing
- */
- const ENTITY = 'catalog_product';
- const CACHE_TAG = 'catalog_product';
- protected $_cacheTag = 'catalog_product';
- protected $_eventPrefix = 'catalog_product';
- protected $_eventObject = 'product';
- protected $_canAffectOptions = false;
- /**
- * Product type instance
- *
- * @var Mage_Catalog_Model_Product_Type_Abstract
- */
- protected $_typeInstance = null;
- /**
- * Product type instance as singleton
- */
- protected $_typeInstanceSingleton = null;
- /**
- * Product link instance
- *
- * @var Mage_Catalog_Model_Product_Link
- */
- protected $_linkInstance;
- /**
- * Product object customization (not stored in DB)
- *
- * @var array
- */
- protected $_customOptions = array();
- /**
- * Product Url Instance
- *
- * @var Mage_Catalog_Model_Product_Url
- */
- protected $_urlModel = null;
- protected static $_url;
- protected static $_urlRewrite;
- protected $_errors = array();
- protected $_optionInstance;
- protected $_options = array();
- /**
- * Product reserved attribute codes
- */
- protected $_reservedAttributes;
- /**
- * Flag for available duplicate function
- *
- * @var boolean
- */
- protected $_isDuplicable = true;
- /**
- * Initialize resources
- */
- protected function _construct()
- {
- $this->_init('catalog/product');
- }
- /**
- * Retrieve Store Id
- *
- * @return int
- */
- public function getStoreId()
- {
- if ($this->hasData('store_id')) {
- return $this->getData('store_id');
- }
- return Mage::app()->getStore()->getId();
- }
- /**
- * Get collection instance
- *
- * @return object
- */
- public function getResourceCollection()
- {
- if (empty($this->_resourceCollectionName)) {
- Mage::throwException(Mage::helper('core')->__('The model collection resource name is not defined.'));
- }
- $collection = Mage::getResourceModel($this->_resourceCollectionName);
- $collection->setStoreId($this->getStoreId());
- return $collection;
- }
- /**
- * Get product url model
- *
- * @return Mage_Catalog_Model_Product_Url
- */
- public function getUrlModel()
- {
- if ($this->_urlModel === null) {
- $this->_urlModel = Mage::getSingleton('catalog/product_url');
- }
- return $this->_urlModel;
- }
- /**
- * Validate Product Data
- *
- * @todo implement full validation process with errors returning which are ignoring now
- *
- * @return Mage_Catalog_Model_Product
- */
- public function validate()
- {
- // $this->getAttributes();
- // Mage::dispatchEvent($this->_eventPrefix.'_validate_before', array($this->_eventObject=>$this));
- // $result = $this->_getResource()->validate($this);
- // Mage::dispatchEvent($this->_eventPrefix.'_validate_after', array($this->_eventObject=>$this));
- // return $result;
- Mage::dispatchEvent($this->_eventPrefix.'_validate_before', array($this->_eventObject=>$this));
- $this->_getResource()->validate($this);
- Mage::dispatchEvent($this->_eventPrefix.'_validate_after', array($this->_eventObject=>$this));
- return $this;
- }
- /**
- * Get product name
- *
- * @return string
- */
- public function getName()
- {
- return $this->_getData('name');
- }
- /**
- * Get product price throught type instance
- *
- * @return unknown
- */
- public function getPrice()
- {
- return $this->getPriceModel()->getPrice($this);
- }
- /**
- * Get product type identifier
- *
- * @return string
- */
- public function getTypeId()
- {
- return $this->_getData('type_id');
- }
- /**
- * Get product status
- *
- * @return int
- */
- public function getStatus()
- {
- return $this->_getData('status');
- }
- /**
- * Retrieve type instance
- *
- * Type instance implement type depended logic
- *
- * @param bool $singleton
- * @return Mage_Catalog_Model_Product_Type_Abstract
- */
- public function getTypeInstance($singleton = false)
- {
- if ($singleton === true) {
- if (is_null($this->_typeInstanceSingleton)) {
- $this->_typeInstanceSingleton = Mage::getSingleton('catalog/product_type')
- ->factory($this, true);
- }
- return $this->_typeInstanceSingleton;
- }
- if ($this->_typeInstance === null) {
- $this->_typeInstance = Mage::getSingleton('catalog/product_type')
- ->factory($this);
- }
- return $this->_typeInstance;
- }
- /**
- * Set type instance for external
- *
- * @param Mage_Catalog_Model_Product_Type_Abstract $singleton
- * @param bool $singleton
- * @return Mage_Catalog_Model_Product
- */
- public function setTypeInstance($instance, $singleton = false)
- {
- if ($singleton === true) {
- $this->_typeInstanceSingleton = $instance;
- } else {
- $this->_typeInstance = $instance;
- }
- return $this;
- }
- /**
- * Retrieve link instance
- *
- * @return Mage_Catalog_Model_Product_Link
- */
- public function getLinkInstance()
- {
- if (!$this->_linkInstance) {
- $this->_linkInstance = Mage::getSingleton('catalog/product_link');
- }
- return $this->_linkInstance;
- }
- /**
- * Retrive product id by sku
- *
- * @param string $sku
- * @return integer
- */
- public function getIdBySku($sku)
- {
- return $this->_getResource()->getIdBySku($sku);
- }
- /**
- * Retrieve product category id
- *
- * @return int
- */
- public function getCategoryId()
- {
- if ($category = Mage::registry('current_category')) {
- return $category->getId();
- }
- return false;
- }
- /**
- * Retrieve product category
- *
- * @return Mage_Catalog_Model_Category
- */
- public function getCategory()
- {
- $category = $this->getData('category');
- if (is_null($category) && $this->getCategoryId()) {
- $category = Mage::getModel('catalog/category')->load($this->getCategoryId());
- $this->setCategory($category);
- }
- return $category;
- }
- /**
- * Set assigned category IDs array to product
- *
- * @param array|string $ids
- * @return Mage_Catalog_Model_Product
- */
- public function setCategoryIds($ids)
- {
- if (is_string($ids)) {
- $ids = explode(',', $ids);
- } elseif (!is_array($ids)) {
- Mage::throwException(Mage::helper('catalog')->__('Invalid category IDs.'));
- }
- foreach ($ids as $i => $v) {
- if (empty($v)) {
- unset($ids[$i]);
- }
- }
- $this->setData('category_ids', $ids);
- return $this;
- }
- /**
- * Retrieve assigned category Ids
- *
- * @return array
- */
- public function getCategoryIds()
- {
- if (! $this->hasData('category_ids')) {
- $wasLocked = false;
- if ($this->isLockedAttribute('category_ids')) {
- $wasLocked = true;
- $this->unlockAttribute('category_ids');
- }
- $ids = $this->_getResource()->getCategoryIds($this);
- $this->setData('category_ids', $ids);
- if ($wasLocked) {
- $this->lockAttribute('category_ids');
- }
- }
- return (array) $this->_getData('category_ids');
- }
- /**
- * Retrieve product categories
- *
- * @return Varien_Data_Collection
- */
- public function getCategoryCollection()
- {
- return $this->_getResource()->getCategoryCollection($this);
- }
- /**
- * Retrieve product websites identifiers
- *
- * @return array
- */
- public function getWebsiteIds()
- {
- if (!$this->hasWebsiteIds()) {
- $ids = $this->_getResource()->getWebsiteIds($this);
- $this->setWebsiteIds($ids);
- }
- return $this->getData('website_ids');
- }
- /**
- * Get all sore ids where product is presented
- *
- * @return array
- */
- public function getStoreIds()
- {
- if (!$this->hasStoreIds()) {
- $storeIds = array();
- if ($websiteIds = $this->getWebsiteIds()) {
- foreach ($websiteIds as $websiteId) {
- $websiteStores = Mage::app()->getWebsite($websiteId)->getStoreIds();
- $storeIds = array_merge($storeIds, $websiteStores);
- }
- }
- $this->setStoreIds($storeIds);
- }
- return $this->getData('store_ids');
- }
- /**
- * Retrieve product attributes
- *
- * if $groupId is null - retrieve all product attributes
- *
- * @param int $groupId
- * @return array
- */
- public function getAttributes($groupId = null, $skipSuper=false)
- {
- $productAttributes = $this->getTypeInstance(true)->getEditableAttributes($this);
- if ($groupId) {
- $attributes = array();
- foreach ($productAttributes as $attribute) {
- if ($attribute->isInGroup($this->getAttributeSetId(), $groupId)) {
- $attributes[] = $attribute;
- }
- }
- } else {
- $attributes = $productAttributes;
- }
- return $attributes;
- }
- /**
- * Check product options and type options and save them, too
- */
- protected function _beforeSave()
- {
- $this->cleanCache();
- $this->setTypeHasOptions(false);
- $this->setTypeHasRequiredOptions(false);
- $this->getTypeInstance(true)->beforeSave($this);
- $hasOptions = false;
- $hasRequiredOptions = false;
- /**
- * $this->_canAffectOptions - set by type instance only
- * $this->getCanSaveCustomOptions() - set either in controller when "Custom Options" ajax tab is loaded,
- * or in type instance as well
- */
- $this->canAffectOptions($this->_canAffectOptions && $this->getCanSaveCustomOptions());
- if ($this->getCanSaveCustomOptions()) {
- $options = $this->getProductOptions();
- if (is_array($options)) {
- $this->setIsCustomOptionChanged(true);
- foreach ($this->getProductOptions() as $option) {
- $this->getOptionInstance()->addOption($option);
- if ((!isset($option['is_delete'])) || $option['is_delete'] != '1') {
- $hasOptions = true;
- }
- }
- foreach ($this->getOptionInstance()->getOptions() as $option) {
- if ($option['is_require'] == '1') {
- $hasRequiredOptions = true;
- break;
- }
- }
- }
- }
- /**
- * Set true, if any
- * Set false, ONLY if options have been affected by Options tab and Type instance tab
- */
- if ($hasOptions || (bool)$this->getTypeHasOptions()) {
- $this->setHasOptions(true);
- if ($hasRequiredOptions || (bool)$this->getTypeHasRequiredOptions()) {
- $this->setRequiredOptions(true);
- } elseif ($this->canAffectOptions()) {
- $this->setRequiredOptions(false);
- }
- } elseif ($this->canAffectOptions()) {
- $this->setHasOptions(false);
- $this->setRequiredOptions(false);
- }
- parent::_beforeSave();
- }
- /**
- * Check/set if options can be affected when saving product
- * If value specified, it will be set.
- *
- * @param bool $value
- * @return bool
- */
- public function canAffectOptions($value = null)
- {
- if (null !== $value) {
- $this->_canAffectOptions = (bool)$value;
- }
- return $this->_canAffectOptions;
- }
- /**
- * Saving product type related data
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _afterSave()
- {
- $this->getLinkInstance()->saveProductRelations($this);
- $this->getTypeInstance(true)->save($this);
- /**
- * Product Options
- */
- $this->getOptionInstance()->setProduct($this)
- ->saveOptions();
- return parent::_afterSave();
- }
- /**
- * Init indexing process after product data commit
- *
- * @return Mage_Catalog_Model_Product
- */
- public function afterCommitCallback()
- {
- parent::afterCommitCallback();
- Mage::getSingleton('index/indexer')->processEntityAction(
- $this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE
- );
- return $this;
- }
- /**
- * Clear chache related with product and protect delete from not admin
- * Register indexing event before delete product
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _beforeDelete()
- {
- $this->_protectFromNonAdmin();
- $this->cleanCache();
- Mage::getSingleton('index/indexer')->logEvent(
- $this, self::ENTITY, Mage_Index_Model_Event::TYPE_DELETE
- );
- return parent::_beforeDelete();
- }
- /**
- * Init indexing process after product delete commit
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _afterDeleteCommit()
- {
- parent::_afterDeleteCommit();
- Mage::getSingleton('index/indexer')->indexEvents(
- self::ENTITY, Mage_Index_Model_Event::TYPE_DELETE
- );
- }
- /**
- * Load product options if they exists
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _afterLoad()
- {
- parent::_afterLoad();
- /**
- * Load product options
- */
- if ($this->getHasOptions()) {
- foreach ($this->getProductOptionsCollection() as $option) {
- $option->setProduct($this);
- $this->addOption($option);
- }
- }
- return $this;
- }
- /**
- * Retrieve resource instance wrapper
- *
- * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product
- */
- protected function _getResource()
- {
- return parent::_getResource();
- }
- /**
- * Clear cache related with product id
- *
- * @return Mage_Catalog_Model_Product
- */
- public function cleanCache()
- {
- Mage::app()->cleanCache('catalog_product_'.$this->getId());
- return $this;
- }
- /**
- * Get product price model
- *
- * @return Mage_Catalog_Model_Product_Type_Price
- */
- public function getPriceModel()
- {
- return Mage::getSingleton('catalog/product_type')->priceFactory($this->getTypeId());
- }
- /**
- * Get product tier price by qty
- *
- * @param double $qty
- * @return double
- */
- public function getTierPrice($qty=null)
- {
- return $this->getPriceModel()->getTierPrice($qty, $this);
- }
- /**
- * Count how many tier prices we have for the product
- *
- * @return int
- */
- public function getTierPriceCount()
- {
- return $this->getPriceModel()->getTierPriceCount($this);
- }
- /**
- * Get formated by currency tier price
- *
- * @param double $qty
- * @return array || double
- */
- public function getFormatedTierPrice($qty=null)
- {
- return $this->getPriceModel()->getFormatedTierPrice($qty, $this);
- }
- /**
- * Get formated by currency product price
- *
- * @return array || double
- */
- public function getFormatedPrice()
- {
- return $this->getPriceModel()->getFormatedPrice($this);
- }
- /**
- * Sets final price of product
- *
- * This func is equal to magic 'setFinalPrice()', but added as a separate func, because in cart with bundle
- * products it's called very often in Item->getProduct(). So removing chain of magic with more cpu consuming
- * algorithms gives nice optimization boost.
- *
- * @return Mage_Catalog_Model_Product
- */
- public function setFinalPrice($price)
- {
- $this->_data['final_price'] = $price;
- return $this;
- }
- /**
- * Get product final price
- *
- * @param double $qty
- * @return double
- */
- public function getFinalPrice($qty=null)
- {
- $price = $this->_getData('final_price');
- if ($price !== null) {
- return $price;
- }
- return $this->getPriceModel()->getFinalPrice($qty, $this);
- }
- public function getCalculatedFinalPrice()
- {
- return $this->_getData('calculated_final_price');
- }
- public function getMinimalPrice()
- {
- return max($this->_getData('minimal_price'), 0);
- }
- public function getSpecialPrice()
- {
- return $this->_getData('special_price');
- }
- public function getSpecialFromDate()
- {
- return $this->_getData('special_from_date');
- }
- public function getSpecialToDate()
- {
- return $this->_getData('special_to_date');
- }
- /*******************************************************************************
- ** Linked products API
- */
- /**
- * Retrieve array of related roducts
- *
- * @return array
- */
- public function getRelatedProducts()
- {
- if (!$this->hasRelatedProducts()) {
- $products = array();
- $collection = $this->getRelatedProductCollection();
- foreach ($collection as $product) {
- $products[] = $product;
- }
- $this->setRelatedProducts($products);
- }
- return $this->getData('related_products');
- }
- /**
- * Retrieve related products identifiers
- *
- * @return array
- */
- public function getRelatedProductIds()
- {
- if (!$this->hasRelatedProductIds()) {
- $ids = array();
- foreach ($this->getRelatedProducts() as $product) {
- $ids[] = $product->getId();
- }
- $this->setRelatedProductIds($ids);
- }
- return $this->getData('related_product_ids');
- }
- /**
- * Retrieve collection related product
- */
- public function getRelatedProductCollection()
- {
- $collection = $this->getLinkInstance()->useRelatedLinks()
- ->getProductCollection()
- ->setIsStrongMode();
- $collection->setProduct($this);
- return $collection;
- }
- /**
- * Retrieve collection related link
- */
- public function getRelatedLinkCollection()
- {
- $collection = $this->getLinkInstance()->useRelatedLinks()
- ->getLinkCollection();
- $collection->setProduct($this);
- $collection->addLinkTypeIdFilter();
- $collection->addProductIdFilter();
- $collection->joinAttributes();
- return $collection;
- }
- /**
- * Retrieve array of up sell products
- *
- * @return array
- */
- public function getUpSellProducts()
- {
- if (!$this->hasUpSellProducts()) {
- $products = array();
- foreach ($this->getUpSellProductCollection() as $product) {
- $products[] = $product;
- }
- $this->setUpSellProducts($products);
- }
- return $this->getData('up_sell_products');
- }
- /**
- * Retrieve up sell products identifiers
- *
- * @return array
- */
- public function getUpSellProductIds()
- {
- if (!$this->hasUpSellProductIds()) {
- $ids = array();
- foreach ($this->getUpSellProducts() as $product) {
- $ids[] = $product->getId();
- }
- $this->setUpSellProductIds($ids);
- }
- return $this->getData('up_sell_product_ids');
- }
- /**
- * Retrieve collection up sell product
- */
- public function getUpSellProductCollection()
- {
- $collection = $this->getLinkInstance()->useUpSellLinks()
- ->getProductCollection()
- ->setIsStrongMode();
- $collection->setProduct($this);
- return $collection;
- }
- /**
- * Retrieve collection up sell link
- */
- public function getUpSellLinkCollection()
- {
- $collection = $this->getLinkInstance()->useUpSellLinks()
- ->getLinkCollection();
- $collection->setProduct($this);
- $collection->addLinkTypeIdFilter();
- $collection->addProductIdFilter();
- $collection->joinAttributes();
- return $collection;
- }
- /**
- * Retrieve array of cross sell products
- *
- * @return array
- */
- public function getCrossSellProducts()
- {
- if (!$this->hasCrossSellProducts()) {
- $products = array();
- foreach ($this->getCrossSellProductCollection() as $product) {
- $products[] = $product;
- }
- $this->setCrossSellProducts($products);
- }
- return $this->getData('cross_sell_products');
- }
- /**
- * Retrieve cross sell products identifiers
- *
- * @return array
- */
- public function getCrossSellProductIds()
- {
- if (!$this->hasCrossSellProductIds()) {
- $ids = array();
- foreach ($this->getCrossSellProducts() as $product) {
- $ids[] = $product->getId();
- }
- $this->setCrossSellProductIds($ids);
- }
- return $this->getData('cross_sell_product_ids');
- }
- /**
- * Retrieve collection cross sell product
- *
- * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Link_Product_Collection
- */
- public function getCrossSellProductCollection()
- {
- $collection = $this->getLinkInstance()->useCrossSellLinks()
- ->getProductCollection()
- ->setIsStrongMode();
- $collection->setProduct($this);
- return $collection;
- }
- /**
- * Retrieve collection cross sell link
- */
- public function getCrossSellLinkCollection()
- {
- $collection = $this->getLinkInstance()->useCrossSellLinks()
- ->getLinkCollection();
- $collection->setProduct($this);
- $collection->addLinkTypeIdFilter();
- $collection->addProductIdFilter();
- $collection->joinAttributes();
- return $collection;
- }
- /**
- * Retrieve collection grouped link
- */
- public function getGroupedLinkCollection()
- {
- $collection = $this->getLinkInstance()->useGroupedLinks()
- ->getLinkCollection();
- $collection->setProduct($this);
- $collection->addLinkTypeIdFilter();
- $collection->addProductIdFilter();
- $collection->joinAttributes();
- return $collection;
- }
- /*******************************************************************************
- ** Media API
- */
- /**
- * Retrive attributes for media gallery
- *
- * @return array
- */
- public function getMediaAttributes()
- {
- if (!$this->hasMediaAttributes()) {
- $mediaAttributes = array();
- foreach ($this->getAttributes() as $attribute) {
- if($attribute->getFrontend()->getInputType() == 'media_image') {
- $mediaAttributes[$attribute->getAttributeCode()] = $attribute;
- }
- }
- $this->setMediaAttributes($mediaAttributes);
- }
- return $this->getData('media_attributes');
- }
- /**
- * Retrive media gallery images
- *
- * @return Varien_Data_Collection
- */
- public function getMediaGalleryImages()
- {
- if(!$this->hasData('media_gallery_images') && is_array($this->getMediaGallery('images'))) {
- $images = new Varien_Data_Collection();
- foreach ($this->getMediaGallery('images') as $image) {
- if ($image['disabled']) {
- continue;
- }
- $image['url'] = $this->getMediaConfig()->getMediaUrl($image['file']);
- $image['id'] = isset($image['value_id']) ? $image['value_id'] : null;
- $image['path'] = $this->getMediaConfig()->getMediaPath($image['file']);
- $images->addItem(new Varien_Object($image));
- }
- $this->setData('media_gallery_images', $images);
- }
- return $this->getData('media_gallery_images');
- }
- /**
- * Add image to media gallery
- *
- * @param string $file file path of image in file system
- * @param string|array $mediaAttribute code of attribute with type 'media_image',
- * leave blank if image should be only in gallery
- * @param boolean $move if true, it will move source file
- * @param boolean $exclude mark image as disabled in product page view
- */
- public function addImageToMediaGallery($file, $mediaAttribute=null, $move=false, $exclude=true)
- {
- $attributes = $this->getTypeInstance(true)->getSetAttributes($this);
- if (!isset($attributes['media_gallery'])) {
- return $this;
- }
- $mediaGalleryAttribute = $attributes['media_gallery'];
- /* @var $mediaGalleryAttribute Mage_Catalog_Model_Resource_Eav_Attribute */
- $mediaGalleryAttribute->getBackend()->addImage($this, $file, $mediaAttribute, $move, $exclude);
- return $this;
- }
- /**
- * Retrive product media config
- *
- * @return Mage_Catalog_Model_Product_Media_Config
- */
- public function getMediaConfig()
- {
- return Mage::getSingleton('catalog/product_media_config');
- }
- /**
- * Create duplicate
- *
- * @return Mage_Catalog_Model_Product
- */
- public function duplicate()
- {
- $this->getWebsiteIds();
- $this->getCategoryIds();
- $newProduct = Mage::getModel('catalog/product')->setData($this->getData())
- ->setIsDuplicate(true)
- ->setOriginalId($this->getId())
- ->setSku(null)
- ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_DISABLED)
- ->setCreatedAt(null)
- ->setUpdatedAt(null)
- ->setId(null)
- ->setStoreId(Mage::app()->getStore()->getId());
- Mage::dispatchEvent(
- 'catalog_model_product_duplicate',
- array('current_product'=>$this, 'new_product'=>$newProduct)
- );
- /* @var $newProduct Mage_Catalog_Model_Product */
- // $newOptionsArray = array();
- // $newProduct->setCanSaveCustomOptions(true);
- // foreach ($this->getOptions() as $_option) {
- // /* @var $_option Mage_Catalog_Model_Product_Option */
- // $newOptionsArray[] = $_option->prepareOptionForDuplicate();
- // }
- // $newProduct->setProductOptions($newOptionsArray);
- /* Prepare Related*/
- $data = array();
- $this->getLinkInstance()->useRelatedLinks();
- $attributes = array();
- foreach ($this->getLinkInstance()->getAttributes() as $_attribute) {
- if (isset($_attribute['code'])) {
- $attributes[]=$_attribute['code'];
- }
- }
- foreach ($this->getRelatedLinkCollection() as $_link) {
- $data[$_link->getLinkedProductId()] = $_link->toArray($attributes);
- }
- $newProduct->setRelatedLinkData($data);
- /* Prepare UpSell*/
- $data = array();
- $this->getLinkInstance()->useUpSellLinks();
- $attributes = array();
- foreach ($this->getLinkInstance()->getAttributes() as $_attribute) {
- if (isset($_attribute['code'])) {
- $attributes[]=$_attribute['code'];
- }
- }
- foreach ($this->getUpSellLinkCollection() as $_link) {
- $data[$_link->getLinkedProductId()] = $_link->toArray($attributes);
- }
- $newProduct->setUpSellLinkData($data);
- /* Prepare Cross Sell */
- $data = array();
- $this->getLinkInstance()->useCrossSellLinks();
- $attributes = array();
- foreach ($this->getLinkInstance()->getAttributes() as $_attribute) {
- if (isset($_attribute['code'])) {
- $attributes[]=$_attribute['code'];
- }
- }
- foreach ($this->getCrossSellLinkCollection() as $_link) {
- $data[$_link->getLinkedProductId()] = $_link->toArray($attributes);
- }
- $newProduct->setCrossSellLinkData($data);
- /* Prepare Grouped */
- $data = array();
- $this->getLinkInstance()->useGroupedLinks();
- $attributes = array();
- foreach ($this->getLinkInstance()->getAttributes() as $_attribute) {
- if (isset($_attribute['code'])) {
- $attributes[]=$_attribute['code'];
- }
- }
- foreach ($this->getGroupedLinkCollection() as $_link) {
- $data[$_link->getLinkedProductId()] = $_link->toArray($attributes);
- }
- $newProduct->setGroupedLinkData($data);
- $newProduct->save();
- $this->getOptionInstance()->duplicate($this->getId(), $newProduct->getId());
- $this->getResource()->duplicate($this->getId(), $newProduct->getId());
- // TODO - duplicate product on all stores of the websites it is associated with
- /*if ($storeIds = $this->getWebsiteIds()) {
- foreach ($storeIds as $storeId) {
- $this->setStoreId($storeId)
- ->load($this->getId());
- $newProduct->setData($this->getData())
- ->setSku(null)
- ->setStatus(Mage_Catalog_Model_Product_Status::STATUS_DISABLED)
- ->setId($newId)
- ->save();
- }
- }*/
- return $newProduct;
- }
- public function isSuperGroup()
- {
- return $this->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_GROUPED;
- }
- public function isSuperConfig()
- {
- return $this->isConfigurable();
- }
- /**
- * Check is product grouped
- *
- * @return bool
- */
- public function isGrouped()
- {
- return $this->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_GROUPED;
- }
- /**
- * Check is product configurable
- *
- * @return bool
- */
- public function isConfigurable()
- {
- return $this->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE;
- }
- public function isSuper()
- {
- return $this->isConfigurable() || $this->isGrouped();
- }
- public function getVisibleInCatalogStatuses()
- {
- return Mage::getSingleton('catalog/product_status')->getVisibleStatusIds();
- }
- /**
- * Retrieve visible statuses
- *
- * @return array
- */
- public function getVisibleStatuses()
- {
- return Mage::getSingleton('catalog/product_status')->getVisibleStatusIds();
- }
- /**
- * Check Product visilbe in catalog
- *
- * @return bool
- */
- public function isVisibleInCatalog()
- {
- return in_array($this->getStatus(), $this->getVisibleInCatalogStatuses());
- }
- /**
- * Retrieve visible in site visibilities
- *
- * @return array
- */
- public function getVisibleInSiteVisibilities()
- {
- return Mage::getSingleton('catalog/product_visibility')->getVisibleInSiteIds();
- }
- /**
- * Check Product visible in site
- *
- * @return bool
- */
- public function isVisibleInSiteVisibility()
- {
- return in_array($this->getVisibility(), $this->getVisibleInSiteVisibilities());
- }
- /**
- * Checks product can be duplicated
- *
- * @return boolean
- */
- public function isDuplicable()
- {
- return $this->_isDuplicable;
- }
- /**
- * Set is duplicable flag
- *
- * @param boolean $value
- * @return Mage_Catalog_Model_Product
- */
- public function setIsDuplicable($value)
- {
- $this->_isDuplicable = (boolean) $value;
- return $this;
- }
- /**
- * Check is product available for sale
- *
- * @return bool
- */
- public function isSalable()
- {
- Mage::dispatchEvent('catalog_product_is_salable_before', array(
- 'product' => $this
- ));
- $salable = $this->isAvailable();
- $object = new Varien_Object(array(
- 'product' => $this,
- 'is_salable' => $salable
- ));
- Mage::dispatchEvent('catalog_product_is_salable_after', array(
- 'product' => $this,
- 'salable' => $object
- ));
- return $object->getIsSalable();
- }
- /**
- * Check whether the product type or stock allows to purchase the product
- *
- * @return bool
- */
- public function isAvailable()
- {
- return $this->getTypeInstance(true)->isSalable($this);
- }
- /**
- * Check is a virtual product
- * Data helper wraper
- *
- * @return bool
- */
- public function isVirtual()
- {
- return $this->getIsVirtual();
- }
- /**
- * Whether the product is a recurring payment
- *
- * @return bool
- */
- public function isRecurring()
- {
- return $this->getIsRecurring() == '1';
- }
- public function isSaleable()
- {
- return $this->isSalable();
- }
- public function isInStock()
- {
- return $this->getStatus() == Mage_Catalog_Model_Product_Status::STATUS_ENABLED;
- }
- public function getAttributeText($attributeCode)
- {
- return $this->getResource()
- ->getAttribute($attributeCode)
- ->getSource()
- ->getOptionText($this->getData($attributeCode));
- }
- public function getCustomDesignDate()
- {
- $result = array();
- $result['from'] = $this->getData('custom_design_from');
- $result['to'] = $this->getData('custom_design_to');
- return $result;
- }
- /**
- * Retrieve Product URL
- *
- * @param bool $useSid
- * @return string
- */
- public function getProductUrl($useSid = null)
- {
- return $this->getUrlModel()->getProductUrl($this, $useSid);
- }
- /**
- * Retrieve URL in current store
- *
- * @param array $params the route params
- * @return string
- */
- public function getUrlInStore($params = array())
- {
- return $this->getUrlModel()->getUrlInStore($this, $params);
- }
- public function formatUrlKey($str)
- {
- return $this->getUrlModel()->formatUrlKey($str);
- }
- /**
- * Retrieve Product Url Path (include category)
- *
- * @param Mage_Catalog_Model_Category $category
- * @return string
- */
- public function getUrlPath($category=null)
- {
- return $this->getUrlModel()->getUrlPath($this, $category);
- }
- public function addAttributeUpdate($code, $value, $store)
- {
- $oldValue = $this->getData($code);
- $oldStore = $this->getStoreId();
- $this->setData($code, $value);
- $this->setStoreId($store);
- $this->getResource()->saveAttribute($this, $code);
- $this->setData($code, $oldValue);
- $this->setStoreId($oldStore);
- }
- public function toArray(array $arrAttributes=array())
- {
- $data = parent::toArray($arrAttributes);
- if ($stock = $this->getStockItem()) {
- $data['stock_item'] = $stock->toArray();
- }
- unset($data['stock_item']['product']);
- return $data;
- }
- public function fromArray($data)
- {
- if (isset($data['stock_item'])) {
- $stockItem = Mage::getModel('cataloginventory/stock_item')
- ->setData($data['stock_item'])
- ->setProduct($this);
- $this->setStockItem($stockItem);
- unset($data['stock_item']);
- }
- $this->setData($data);
- return $this;
- }
- /**
- * @deprecated after 1.4.2.0
- * @return Mage_Catalog_Model_Product
- */
- public function loadParentProductIds()
- {
- return $this->setParentProductIds(array());
- }
- public function delete()
- {
- parent::delete();
- Mage::dispatchEvent($this->_eventPrefix.'_delete_after_done', array($this->_eventObject=>$this));
- return $this;
- }
- public function getRequestPath()
- {
- return $this->_getData('request_path');
- }
- /**
- * Custom function for other modules
- */
- public function getGiftMessageAvailable()
- {
- return $this->_getData('gift_message_available');
- }
- public function getRatingSummary()
- {
- return $this->_getData('rating_summary');
- }
- /**
- * Check is product composite
- *
- * @return bool
- */
- public function isComposite()
- {
- return $this->getTypeInstance(true)->isComposite($this);
- }
- /**
- * Check if product can be configured
- *
- * @return bool
- */
- public function canConfigure()
- {
- $options = $this->getOptions();
- return !empty($options) || $this->getTypeInstance(true)->canConfigure($this);
- }
- /**
- * Retrieve sku through type instance
- *
- * @return string
- */
- public function getSku()
- {
- return $this->getTypeInstance(true)->getSku($this);
- }
- /**
- * Retrieve weight throught type instance
- *
- * @return unknown
- */
- public function getWeight()
- {
- return $this->getTypeInstance(true)->getWeight($this);
- }
- /**
- * Retrieve option instance
- *
- * @return Mage_Catalog_Model_Product_Option
- */
- public function getOptionInstance()
- {
- if (!$this->_optionInstance) {
- $this->_optionInstance = Mage::getSingleton('catalog/product_option');
- }
- return $this->_optionInstance;
- }
- /**
- * Retrieve options collection of product
- *
- * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option_Collection
- */
- public function getProductOptionsCollection()
- {
- $collection = $this->getOptionInstance()
- ->getProductOptionCollection($this);
- return $collection;
- }
- /**
- * Add option to array of product options
- *
- * @param Mage_Catalog_Model_Product_Option $option
- * @return Mage_Catalog_Model_Product
- */
- public function addOption(Mage_Catalog_Model_Product_Option $option)
- {
- $this->_options[$option->getId()] = $option;
- return $this;
- }
- /**
- * Get option from options array of product by given option id
- *
- * @param int $optionId
- * @return Mage_Catalog_Model_Product_Option | null
- */
- public function getOptionById($optionId)
- {
- if (isset($this->_options[$optionId])) {
- return $this->_options[$optionId];
- }
- return null;
- }
- /**
- * Get all options of product
- *
- * @return array
- */
- public function getOptions()
- {
- return $this->_options;
- }
- /**
- * Retrieve is a virtual product
- *
- * @return bool
- */
- public function getIsVirtual()
- {
- return $this->getTypeInstance(true)->isVirtual($this);
- }
- /**
- * Add custom option information to product
- *
- * @param string $code
- * @param mixed $value
- * @param int $productId
- * @return Mage_Catalog_Model_Product
- */
- public function addCustomOption($code, $value, $product=null)
- {
- $product = $product ? $product : $this;
- $option = Mage::getModel('catalog/product_configuration_item_option')
- ->addData(array(
- 'product_id'=> $product->getId(),
- 'product' => $product,
- 'code' => $code,
- 'value' => $value,
- ));
- $this->_customOptions[$code] = $option;
- return $this;
- }
- public function setCustomOptions(array $options)
- {
- $this->_customOptions = $options;
- }
- /**
- * Get all custom options of the product
- *
- * @return array
- */
- public function getCustomOptions()
- {
- return $this->_customOptions;
- }
- /**
- * Get product custom option info
- *
- * @param string $code
- * @return array
- */
- public function getCustomOption($code)
- {
- if (isset($this->_customOptions[$code])) {
- return $this->_customOptions[$code];
- }
- return null;
- }
- /**
- * Checks if there custom option for this product
- *
- * @return bool
- */
- public function hasCustomOptions()
- {
- if (count($this->_customOptions)) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * Check availability display product in category
- *
- * @param int $categoryId
- * @return bool
- */
- public function canBeShowInCategory($categoryId)
- {
- return $this->_getResource()->canBeShowInCategory($this, $categoryId);
- }
- /**
- * Retrieve category ids where product is available
- *
- * @return array
- */
- public function getAvailableInCategories()
- {
- return $this->_getResource()->getAvailableInCategories($this);
- }
- /**
- * Retrieve default attribute set id
- *
- * @return int
- */
- public function getDefaultAttributeSetId()
- {
- return $this->getResource()->getEntityType()->getDefaultAttributeSetId();
- }
- /**
- * Deprecated since 1.1.5
- */
- public function getImageUrl()
- {
- return (string)Mage::helper('catalog/image')->init($this, 'image')->resize(265);
- }
- /**
- * Deprecated since 1.1.5
- */
- public function getSmallImageUrl($width = 88, $height = 77)
- {
- return (string)Mage::helper('catalog/image')->init($this, 'small_image')->resize($width, $height);
- }
- /**
- * Deprecated since 1.1.5
- */
- public function getThumbnailUrl($width = 75, $height = 75)
- {
- return (string)Mage::helper('catalog/image')->init($this, 'thumbnail')->resize($width, $height);
- }
- /**
- * Returns system reserved attribute codes
- *
- * @return array Reserved attribute names
- */
- public function getReservedAttributes()
- {
- if ($this->_reservedAttributes === null) {
- $_reserved = array('position');
- $methods = get_class_methods(__CLASS__);
- foreach ($methods as $method) {
- if (preg_match('/^get([A-Z]{1}.+)/', $method, $matches)) {
- $method = $matches[1];
- $tmp = strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $method));
- $_reserved[] = $tmp;
- }
- }
- $_allowed = array(
- 'type_id','calculated_final_price','request_path','rating_summary'
- );
- $this->_reservedAttributes = array_diff($_reserved, $_allowed);
- }
- return $this->_reservedAttributes;
- }
- /**
- * Check whether attribute reserved or not
- *
- * @param Mage_Eav_Model_Entity_Attribute $attribute Attribute model object
- * @return boolean
- */
- public function isReservedAttribute ($attribute)
- {
- return $attribute->getIsUserDefined()
- && in_array($attribute->getAttributeCode(), $this->getReservedAttributes());
- }
- /**
- * Set original loaded data if needed
- *
- * @param string $key
- * @param mixed $data
- * @return Varien_Object
- */
- public function setOrigData($key=null, $data=null)
- {
- if (Mage::app()->getStore()->isAdmin()) {
- return parent::setOrigData($key, $data);
- }
- return $this;
- }
- /**
- * @deprecated
- * @see Mage_Sales_Model_Observer::substractQtyFromQuotes()
- */
- protected function _substractQtyFromQuotes()
- {
- // kept for legacy purposes
- }
- /**
- * Reset all model data
- *
- * @return Mage_Catalog_Model_Product
- */
- public function reset()
- {
- $this->_clearData();
- return $this;
- }
- /**
- * Get cahce tags associated with object id
- *
- * @return array
- */
- public function getCacheIdTags()
- {
- $tags = parent::getCacheIdTags();
- $affectedCategoryIds = $this->getAffectedCategoryIds();
- if (!$affectedCategoryIds) {
- $affectedCategoryIds = $this->getCategoryIds();
- }
- foreach ($affectedCategoryIds as $categoryId) {
- $tags[] = Mage_Catalog_Model_Category::CACHE_TAG.'_'.$categoryId;
- }
- return $tags;
- }
- /**
- * Check for empty SKU on each product
- *
- * @param array $productIds
- * @return boolean|null
- */
- public function isProductsHasSku(array $productIds)
- {
- $products = $this->_getResource()->getProductsSku($productIds);
- if (count($products)) {
- foreach ($products as $product) {
- if (empty($product['sku'])) {
- return false;
- }
- }
- return true;
- }
- return null;
- }
- /**
- * Parse buyRequest into options values used by product
- *
- * @param Varien_Object $buyRequest
- * @return Varien_Object
- */
- public function processBuyRequest(Varien_Object $buyRequest)
- {
- $options = new Varien_Object();
- /* add product custom options data */
- $customOptions = $buyRequest->getOptions();
- if (is_array($customOptions)) {
- $options->setOptions(array_diff($buyRequest->getOptions(), array('')));
- }
- /* add product type selected options data */
- $type = $this->getTypeInstance(true);
- $typeSpecificOptions = $type->processBuyRequest($this, $buyRequest);
- $options->addData($typeSpecificOptions);
- /* check correctness of product's options */
- $options->setErrors($type->checkProductConfiguration($this, $buyRequest));
- return $options;
- }
- /**
- * Get preconfigured values from product
- *
- * @return Varien_Object
- */
- public function getPreconfiguredValues()
- {
- $preconfiguredValues = $this->getData('preconfigured_values');
- if (!$preconfiguredValues) {
- $preconfiguredValues = new Varien_Object();
- }
- return $preconfiguredValues;
- }
- /**
- * Prepare product custom options.
- * To be sure that all product custom options does not has ID and has product instance
- *
- * @return Mage_Catalog_Model_Product
- */
- public function prepareCustomOptions()
- {
- foreach ($this->getCustomOptions() as $option) {
- if (!is_object($option->getProduct()) || $option->getId()) {
- $this->addCustomOption($option->getCode(), $option->getValue());
- }
- }
- return $this;
- }
- /**
- * Clearing references on product
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _clearReferences()
- {
- $this->_clearOptionReferences();
- return $this;
- }
- /**
- * Clearing product's data
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _clearData()
- {
- foreach ($this->_data as $data){
- if (is_object($data) && method_exists($data, 'reset')){
- $data->reset();
- }
- }
- $this->setData(array());
- $this->setOrigData();
- $this->_customOptions = array();
- $this->_optionInstance = null;
- $this->_options = array();
- $this->_canAffectOptions = false;
- $this->_errors = array();
- return $this;
- }
- /**
- * Clearing references to product from product's options
- *
- * @return Mage_Catalog_Model_Product
- */
- protected function _clearOptionReferences()
- {
- /**
- * unload product options
- */
- if (!empty($this->_options)) {
- foreach ($this->_options as $key => $option) {
- $option->setProduct();
- $option->clearInstance();
- }
- }
- return $this;
- }
- }