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: * Catalog attribute model
29: *
30: * @method Mage_Catalog_Model_Resource_Attribute _getResource()
31: * @method Mage_Catalog_Model_Resource_Attribute getResource()
32: * @method Mage_Catalog_Model_Resource_Eav_Attribute getFrontendInputRenderer()
33: * @method string setFrontendInputRenderer(string $value)
34: * @method int setIsGlobal(int $value)
35: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsVisible()
36: * @method int setIsVisible(int $value)
37: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsSearchable()
38: * @method int setIsSearchable(int $value)
39: * @method Mage_Catalog_Model_Resource_Eav_Attribute getSearchWeight()
40: * @method int setSearchWeight(int $value)
41: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsFilterable()
42: * @method int setIsFilterable(int $value)
43: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsComparable()
44: * @method int setIsComparable(int $value)
45: * @method int setIsVisibleOnFront(int $value)
46: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsHtmlAllowedOnFront()
47: * @method int setIsHtmlAllowedOnFront(int $value)
48: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsUsedForPriceRules()
49: * @method int setIsUsedForPriceRules(int $value)
50: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsFilterableInSearch()
51: * @method int setIsFilterableInSearch(int $value)
52: * @method Mage_Catalog_Model_Resource_Eav_Attribute getUsedInProductListing()
53: * @method int setUsedInProductListing(int $value)
54: * @method Mage_Catalog_Model_Resource_Eav_Attribute getUsedForSortBy()
55: * @method int setUsedForSortBy(int $value)
56: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsConfigurable()
57: * @method int setIsConfigurable(int $value)
58: * @method string setApplyTo(string $value)
59: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsVisibleInAdvancedSearch()
60: * @method int setIsVisibleInAdvancedSearch(int $value)
61: * @method Mage_Catalog_Model_Resource_Eav_Attribute getPosition()
62: * @method int setPosition(int $value)
63: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsWysiwygEnabled()
64: * @method int setIsWysiwygEnabled(int $value)
65: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsUsedForPromoRules()
66: * @method int setIsUsedForPromoRules(int $value)
67: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsUsedForCustomerSegment()
68: * @method int setIsUsedForCustomerSegment(int $value)
69: * @method Mage_Catalog_Model_Resource_Eav_Attribute getIsUsedForTargetRules()
70: * @method int setIsUsedForTargetRules(int $value)
71: *
72: * @category Mage
73: * @package Mage_Catalog
74: * @author Magento Core Team <core@magentocommerce.com>
75: */
76: class Mage_Catalog_Model_Resource_Eav_Attribute extends Mage_Eav_Model_Entity_Attribute
77: {
78: const SCOPE_STORE = 0;
79: const SCOPE_GLOBAL = 1;
80: const SCOPE_WEBSITE = 2;
81:
82: const MODULE_NAME = 'Mage_Catalog';
83: const ENTITY = 'catalog_eav_attribute';
84:
85: /**
86: * Event prefix
87: *
88: * @var string
89: */
90: protected $_eventPrefix = 'catalog_entity_attribute';
91: /**
92: * Event object name
93: *
94: * @var string
95: */
96: protected $_eventObject = 'attribute';
97:
98: /**
99: * Array with labels
100: *
101: * @var array
102: */
103: static protected $_labels = null;
104:
105: protected function _construct()
106: {
107: $this->_init('catalog/attribute');
108: }
109:
110: /**
111: * Processing object before save data
112: *
113: * @throws Mage_Core_Exception
114: * @return Mage_Core_Model_Abstract
115: */
116: protected function _beforeSave()
117: {
118: $this->setData('modulePrefix', self::MODULE_NAME);
119: if (isset($this->_origData['is_global'])) {
120: if (!isset($this->_data['is_global'])) {
121: $this->_data['is_global'] = self::SCOPE_GLOBAL;
122: }
123: if (($this->_data['is_global'] != $this->_origData['is_global'])
124: && $this->_getResource()->isUsedBySuperProducts($this)) {
125: Mage::throwException(Mage::helper('catalog')->__('Scope must not be changed, because the attribute is used in configurable products.'));
126: }
127: }
128: if ($this->getFrontendInput() == 'price') {
129: if (!$this->getBackendModel()) {
130: $this->setBackendModel('catalog/product_attribute_backend_price');
131: }
132: }
133: if ($this->getFrontendInput() == 'textarea') {
134: if ($this->getIsWysiwygEnabled()) {
135: $this->setIsHtmlAllowedOnFront(1);
136: }
137: }
138: return parent::_beforeSave();
139: }
140:
141: /**
142: * Processing object after save data
143: *
144: * @return Mage_Core_Model_Abstract
145: */
146: protected function _afterSave()
147: {
148: /**
149: * Fix saving attribute in admin
150: */
151: Mage::getSingleton('eav/config')->clear();
152:
153: Mage::getSingleton('index/indexer')->processEntityAction(
154: $this, self::ENTITY, Mage_Index_Model_Event::TYPE_SAVE
155: );
156: return parent::_afterSave();
157: }
158:
159: /**
160: * Register indexing event before delete catalog eav attribute
161: *
162: * @return Mage_Catalog_Model_Resource_Eav_Attribute
163: */
164: protected function _beforeDelete()
165: {
166: if ($this->_getResource()->isUsedBySuperProducts($this)) {
167: Mage::throwException(Mage::helper('catalog')->__('This attribute is used in configurable products.'));
168: }
169: Mage::getSingleton('index/indexer')->logEvent(
170: $this, self::ENTITY, Mage_Index_Model_Event::TYPE_DELETE
171: );
172: return parent::_beforeDelete();
173: }
174:
175: /**
176: * Init indexing process after catalog eav attribute delete commit
177: *
178: * @return Mage_Catalog_Model_Resource_Eav_Attribute
179: */
180: protected function _afterDeleteCommit()
181: {
182: parent::_afterDeleteCommit();
183: Mage::getSingleton('index/indexer')->indexEvents(
184: self::ENTITY, Mage_Index_Model_Event::TYPE_DELETE
185: );
186: return $this;
187: }
188:
189: /**
190: * Return is attribute global
191: *
192: * @return integer
193: */
194: public function getIsGlobal()
195: {
196: return $this->_getData('is_global');
197: }
198:
199: /**
200: * Retrieve attribute is global scope flag
201: *
202: * @return bool
203: */
204: public function isScopeGlobal()
205: {
206: return $this->getIsGlobal() == self::SCOPE_GLOBAL;
207: }
208:
209: /**
210: * Retrieve attribute is website scope website
211: *
212: * @return bool
213: */
214: public function isScopeWebsite()
215: {
216: return $this->getIsGlobal() == self::SCOPE_WEBSITE;
217: }
218:
219: /**
220: * Retrieve attribute is store scope flag
221: *
222: * @return bool
223: */
224: public function isScopeStore()
225: {
226: return !$this->isScopeGlobal() && !$this->isScopeWebsite();
227: }
228:
229: /**
230: * Retrieve store id
231: *
232: * @return int
233: */
234: public function getStoreId()
235: {
236: $dataObject = $this->getDataObject();
237: if ($dataObject) {
238: return $dataObject->getStoreId();
239: }
240: return $this->getData('store_id');
241: }
242:
243: /**
244: * Retrieve apply to products array
245: * Return empty array if applied to all products
246: *
247: * @return array
248: */
249: public function getApplyTo()
250: {
251: if ($this->getData('apply_to')) {
252: if (is_array($this->getData('apply_to'))) {
253: return $this->getData('apply_to');
254: }
255: return explode(',', $this->getData('apply_to'));
256: } else {
257: return array();
258: }
259: }
260:
261: /**
262: * Retrieve source model
263: *
264: * @return Mage_Eav_Model_Entity_Attribute_Source_Abstract
265: */
266: public function getSourceModel()
267: {
268: $model = $this->getData('source_model');
269: if (empty($model)) {
270: if ($this->getBackendType() == 'int' && $this->getFrontendInput() == 'select') {
271: return $this->_getDefaultSourceModel();
272: }
273: }
274: return $model;
275: }
276:
277: /**
278: * Check is allow for rule condition
279: *
280: * @return bool
281: */
282: public function isAllowedForRuleCondition()
283: {
284: $allowedInputTypes = array('text', 'multiselect', 'textarea', 'date', 'datetime', 'select', 'boolean', 'price');
285: return $this->getIsVisible() && in_array($this->getFrontendInput(), $allowedInputTypes);
286: }
287:
288: /**
289: * Retrieve don't translated frontend label
290: *
291: * @return string
292: */
293: public function getFrontendLabel()
294: {
295: return $this->_getData('frontend_label');
296: }
297:
298: /**
299: * Get Attribute translated label for store
300: *
301: * @deprecated
302: * @return string
303: */
304: protected function _getLabelForStore()
305: {
306: return $this->getFrontendLabel();
307: }
308:
309: /**
310: * Initialize store Labels for attributes
311: *
312: * @deprecated
313: * @param int $storeId
314: */
315: public static function initLabels($storeId = null)
316: {
317: if (is_null(self::$_labels)) {
318: if (is_null($storeId)) {
319: $storeId = Mage::app()->getStore()->getId();
320: }
321: $attributeLabels = array();
322: $attributes = Mage::getResourceSingleton('catalog/product')->getAttributesByCode();
323: foreach ($attributes as $attribute) {
324: if (strlen($attribute->getData('frontend_label')) > 0) {
325: $attributeLabels[] = $attribute->getData('frontend_label');
326: }
327: }
328:
329: self::$_labels = Mage::app()->getTranslator()->getResource()
330: ->getTranslationArrayByStrings($attributeLabels, $storeId);
331: }
332: }
333:
334: /**
335: * Get default attribute source model
336: *
337: * @return string
338: */
339: public function _getDefaultSourceModel()
340: {
341: return 'eav/entity_attribute_source_table';
342: }
343:
344: /**
345: * Check is an attribute used in EAV index
346: *
347: * @return bool
348: */
349: public function isIndexable()
350: {
351: // exclude price attribute
352: if ($this->getAttributeCode() == 'price') {
353: return false;
354: }
355:
356: if (!$this->getIsFilterableInSearch() && !$this->getIsVisibleInAdvancedSearch() && !$this->getIsFilterable()) {
357: return false;
358: }
359:
360: $backendType = $this->getBackendType();
361: $frontendInput = $this->getFrontendInput();
362:
363: if ($backendType == 'int' && $frontendInput == 'select') {
364: return true;
365: } else if ($backendType == 'varchar' && $frontendInput == 'multiselect') {
366: return true;
367: } else if ($backendType == 'decimal') {
368: return true;
369: }
370:
371: return false;
372: }
373:
374: /**
375: * Retrieve index type for indexable attribute
376: *
377: * @return string|false
378: */
379: public function getIndexType()
380: {
381: if (!$this->isIndexable()) {
382: return false;
383: }
384: if ($this->getBackendType() == 'decimal') {
385: return 'decimal';
386: }
387:
388: return 'source';
389: }
390: }
391: