*/ abstract class Mage_Rule_Model_Condition_Product_Abstract extends Mage_Rule_Model_Condition_Abstract { /** * All attribute values as array in form: * array( * [entity_id_1] => array( * [store_id_1] => store_value_1, * [store_id_2] => store_value_2, * ... * [store_id_n] => store_value_n * ), * ... * ) * * Will be set only for not global scope attribute * * @var array */ protected $_entityAttributeValues = null; /** * Attribute data key that indicates whether it should be used for rules * * @var string */ protected $_isUsedForRuleProperty = 'is_used_for_promo_rules'; /** * Customize default operator input by type mapper for some types * * @return array */ public function getDefaultOperatorInputByType() { if (null === $this->_defaultOperatorInputByType) { parent::getDefaultOperatorInputByType(); /* * '{}' and '!{}' are left for back-compatibility and equal to '==' and '!=' */ $this->_defaultOperatorInputByType['category'] = array('==', '!=', '{}', '!{}', '()', '!()'); $this->_arrayInputTypes[] = 'category'; } return $this->_defaultOperatorInputByType; } /** * Retrieve attribute object * * @return Mage_Catalog_Model_Resource_Eav_Attribute */ public function getAttributeObject() { try { $obj = Mage::getSingleton('eav/config') ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $this->getAttribute()); } catch (Exception $e) { $obj = new Varien_Object(); $obj->setEntity(Mage::getResourceSingleton('catalog/product')) ->setFrontendInput('text'); } return $obj; } /** * Add special attributes * * @param array $attributes */ protected function _addSpecialAttributes(array &$attributes) { $attributes['attribute_set_id'] = Mage::helper('catalogrule')->__('Attribute Set'); $attributes['category_ids'] = Mage::helper('catalogrule')->__('Category'); } /** * Load attribute options * * @return Mage_CatalogRule_Model_Rule_Condition_Product */ public function loadAttributeOptions() { $productAttributes = Mage::getResourceSingleton('catalog/product') ->loadAllAttributes() ->getAttributesByCode(); $attributes = array(); foreach ($productAttributes as $attribute) { /* @var $attribute Mage_Catalog_Model_Resource_Eav_Attribute */ if (!$attribute->isAllowedForRuleCondition() || !$attribute->getDataUsingMethod($this->_isUsedForRuleProperty) ) { continue; } $attributes[$attribute->getAttributeCode()] = $attribute->getFrontendLabel(); } $this->_addSpecialAttributes($attributes); asort($attributes); $this->setAttributeOption($attributes); return $this; } /** * Prepares values options to be used as select options or hashed array * Result is stored in following keys: * 'value_select_options' - normal select array: array(array('value' => $value, 'label' => $label), ...) * 'value_option' - hashed array: array($value => $label, ...), * * @return Mage_CatalogRule_Model_Rule_Condition_Product */ protected function _prepareValueOptions() { // Check that both keys exist. Maybe somehow only one was set not in this routine, but externally. $selectReady = $this->getData('value_select_options'); $hashedReady = $this->getData('value_option'); if ($selectReady && $hashedReady) { return $this; } // Get array of select options. It will be used as source for hashed options $selectOptions = null; if ($this->getAttribute() === 'attribute_set_id') { $entityTypeId = Mage::getSingleton('eav/config') ->getEntityType(Mage_Catalog_Model_Product::ENTITY)->getId(); $selectOptions = Mage::getResourceModel('eav/entity_attribute_set_collection') ->setEntityTypeFilter($entityTypeId) ->load() ->toOptionArray(); } else if (is_object($this->getAttributeObject())) { $attributeObject = $this->getAttributeObject(); if ($attributeObject->usesSource()) { if ($attributeObject->getFrontendInput() == 'multiselect') { $addEmptyOption = false; } else { $addEmptyOption = true; } $selectOptions = $attributeObject->getSource()->getAllOptions($addEmptyOption); } } // Set new values only if we really got them if ($selectOptions !== null) { // Overwrite only not already existing values if (!$selectReady) { $this->setData('value_select_options', $selectOptions); } if (!$hashedReady) { $hashedOptions = array(); foreach ($selectOptions as $o) { if (is_array($o['value'])) { continue; // We cannot use array as index } $hashedOptions[$o['value']] = $o['label']; } $this->setData('value_option', $hashedOptions); } } return $this; } /** * Retrieve value by option * * @param mixed $option * @return string */ public function getValueOption($option=null) { $this->_prepareValueOptions(); return $this->getData('value_option'.(!is_null($option) ? '/'.$option : '')); } /** * Retrieve select option values * * @return array */ public function getValueSelectOptions() { $this->_prepareValueOptions(); return $this->getData('value_select_options'); } /** * Retrieve after element HTML * * @return string */ public function getValueAfterElementHtml() { $html = ''; switch ($this->getAttribute()) { case 'sku': case 'category_ids': $image = Mage::getDesign()->getSkinUrl('images/rule_chooser_trigger.gif'); break; } if (!empty($image)) { $html = ''; } return $html; } /** * Retrieve attribute element * * @return Varien_Form_Element_Abstract */ public function getAttributeElement() { $element = parent::getAttributeElement(); $element->setShowAsText(true); return $element; } /** * Collect validated attributes * * @param Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection $productCollection * @return Mage_CatalogRule_Model_Rule_Condition_Product */ public function collectValidatedAttributes($productCollection) { $attribute = $this->getAttribute(); if ('category_ids' != $attribute) { if ($this->getAttributeObject()->isScopeGlobal()) { $attributes = $this->getRule()->getCollectedAttributes(); $attributes[$attribute] = true; $this->getRule()->setCollectedAttributes($attributes); $productCollection->addAttributeToSelect($attribute, 'left'); } else { $this->_entityAttributeValues = $productCollection->getAllAttributeValues($attribute); } } return $this; } /** * Retrieve input type * * @return string */ public function getInputType() { if ($this->getAttribute()==='attribute_set_id') { return 'select'; } if (!is_object($this->getAttributeObject())) { return 'string'; } if ($this->getAttributeObject()->getAttributeCode() == 'category_ids') { return 'category'; } switch ($this->getAttributeObject()->getFrontendInput()) { case 'select': return 'select'; case 'multiselect': return 'multiselect'; case 'date': return 'date'; case 'boolean': return 'boolean'; default: return 'string'; } } /** * Retrieve value element type * * @return string */ public function getValueElementType() { if ($this->getAttribute()==='attribute_set_id') { return 'select'; } if (!is_object($this->getAttributeObject())) { return 'text'; } switch ($this->getAttributeObject()->getFrontendInput()) { case 'select': case 'boolean': return 'select'; case 'multiselect': return 'multiselect'; case 'date': return 'date'; default: return 'text'; } } /** * Retrieve value element * * @return Varien_Data_Form_Element_Abstract */ public function getValueElement() { $element = parent::getValueElement(); if (is_object($this->getAttributeObject())) { switch ($this->getAttributeObject()->getFrontendInput()) { case 'date': $element->setImage(Mage::getDesign()->getSkinUrl('images/grid-cal.gif')); break; } } return $element; } /** * Retrieve value element chooser URL * * @return string */ public function getValueElementChooserUrl() { $url = false; switch ($this->getAttribute()) { case 'sku': case 'category_ids': $url = 'adminhtml/promo_widget/chooser' .'/attribute/'.$this->getAttribute(); if ($this->getJsFormObject()) { $url .= '/form/'.$this->getJsFormObject(); } break; } return $url!==false ? Mage::helper('adminhtml')->getUrl($url) : ''; } /** * Retrieve Explicit Apply * * @return bool */ public function getExplicitApply() { switch ($this->getAttribute()) { case 'sku': case 'category_ids': return true; } if (is_object($this->getAttributeObject())) { switch ($this->getAttributeObject()->getFrontendInput()) { case 'date': return true; } } return false; } /** * Load array * * @param array $arr * @return Mage_CatalogRule_Model_Rule_Condition_Product */ public function loadArray($arr) { $this->setAttribute(isset($arr['attribute']) ? $arr['attribute'] : false); $attribute = $this->getAttributeObject(); $isContainsOperator = !empty($arr['operator']) && in_array($arr['operator'], array('{}', '!{}')); if ($attribute && $attribute->getBackendType() == 'decimal' && !$isContainsOperator) { if (isset($arr['value'])) { if (!empty($arr['operator']) && in_array($arr['operator'], array('!()', '()')) && false !== strpos($arr['value'], ',')) { $tmp = array(); foreach (explode(',', $arr['value']) as $value) { $tmp[] = Mage::app()->getLocale()->getNumber($value); } $arr['value'] = implode(',', $tmp); } else { $arr['value'] = Mage::app()->getLocale()->getNumber($arr['value']); } } else { $arr['value'] = false; } $arr['is_value_parsed'] = isset($arr['is_value_parsed']) ? Mage::app()->getLocale()->getNumber($arr['is_value_parsed']) : false; } return parent::loadArray($arr); } /** * Validate product attrbute value for condition * * @param Varien_Object $object * @return bool */ public function validate(Varien_Object $object) { $attrCode = $this->getAttribute(); if ('category_ids' == $attrCode) { return $this->validateAttribute($object->getAvailableInCategories()); } elseif (! isset($this->_entityAttributeValues[$object->getId()])) { if (!$object->getResource()) { return false; } $attr = $object->getResource()->getAttribute($attrCode); if ($attr && $attr->getBackendType() == 'datetime' && !is_int($this->getValue())) { $this->setValue(strtotime($this->getValue())); $value = strtotime($object->getData($attrCode)); return $this->validateAttribute($value); } if ($attr && $attr->getFrontendInput() == 'multiselect') { $value = $object->getData($attrCode); $value = strlen($value) ? explode(',', $value) : array(); return $this->validateAttribute($value); } return parent::validate($object); } else { $result = false; // any valid value will set it to TRUE // remember old attribute state $oldAttrValue = $object->hasData($attrCode) ? $object->getData($attrCode) : null; foreach ($this->_entityAttributeValues[$object->getId()] as $storeId => $value) { $attr = $object->getResource()->getAttribute($attrCode); if ($attr && $attr->getBackendType() == 'datetime') { $value = strtotime($value); } else if ($attr && $attr->getFrontendInput() == 'multiselect') { $value = strlen($value) ? explode(',', $value) : array(); } $object->setData($attrCode, $value); $result |= parent::validate($object); if ($result) { break; } } if (is_null($oldAttrValue)) { $object->unsetData($attrCode); } else { $object->setData($attrCode, $oldAttrValue); } return (bool) $result; } } /** * Correct '==' and '!=' operators * Categories can't be equal because product is included categories selected by administrator and in their parents * * @return string */ public function getOperatorForValidate() { $op = $this->getOperator(); if ($this->getInputType() == 'category') { if ($op == '==') { $op = '{}'; } elseif ($op == '!=') { $op = '!{}'; } } return $op; } }