1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27:
28: 29: 30: 31: 32: 33: 34:
35: abstract class Mage_Eav_Model_Entity_Abstract extends Mage_Core_Model_Resource_Abstract
36: implements Mage_Eav_Model_Entity_Interface
37: {
38: 39: 40: 41: 42:
43: protected $_read;
44:
45: 46: 47: 48: 49:
50: protected $_write;
51:
52: 53: 54: 55: 56:
57: protected $_type;
58:
59: 60: 61: 62: 63:
64: protected $_attributesById = array();
65:
66: 67: 68: 69: 70:
71: protected $_attributesByCode = array();
72:
73: 74: 75: 76: 77:
78: protected $_attributesByTable = array();
79:
80: 81: 82: 83: 84:
85: protected $_staticAttributes = array();
86:
87: 88: 89: 90: 91:
92: protected static $_defaultAttributes = array();
93:
94: 95: 96: 97: 98:
99: protected $_entityTable;
100:
101: 102: 103: 104: 105:
106: protected $_describeTable = array();
107:
108: 109: 110: 111: 112:
113: protected $_entityIdField;
114:
115: 116: 117: 118: 119:
120: protected $_valueEntityIdField;
121:
122: 123: 124: 125: 126:
127: protected $_valueTablePrefix;
128:
129: 130: 131: 132:
133: protected $_entityTablePrefix;
134:
135: 136: 137: 138: 139:
140: protected $_isPartialLoad = false;
141:
142: 143: 144: 145: 146:
147: protected $_isPartialSave = false;
148:
149: 150: 151: 152: 153:
154: protected $_sortingSetId = null;
155:
156: 157: 158: 159: 160:
161: protected $_attributeValuesToDelete = array();
162:
163: 164: 165: 166: 167:
168: protected $_attributeValuesToSave = array();
169:
170: 171: 172: 173: 174: 175:
176: protected static $_attributeBackendTables = array();
177:
178: 179: 180: 181: 182: 183: 184:
185: public function setConnection($read, $write = null)
186: {
187: $this->_read = $read;
188: $this->_write = $write ? $write : $read;
189:
190: return $this;
191: }
192:
193: 194: 195:
196: protected function _construct()
197: {}
198:
199: 200: 201: 202: 203:
204: protected function _getReadAdapter()
205: {
206: if (is_string($this->_read)) {
207: $this->_read = Mage::getSingleton('core/resource')->getConnection($this->_read);
208: }
209: return $this->_read;
210: }
211:
212: 213: 214: 215: 216:
217: protected function _getWriteAdapter()
218: {
219: if (is_string($this->_write)) {
220: $this->_write = Mage::getSingleton('core/resource')->getConnection($this->_write);
221: }
222: return $this->_write;
223: }
224:
225: 226: 227: 228: 229:
230: public function getReadConnection()
231: {
232: return $this->_getReadAdapter();
233: }
234:
235: 236: 237: 238: 239:
240: public function getWriteConnection()
241: {
242: return $this->_getWriteAdapter();
243: }
244:
245: 246: 247: 248: 249:
250: public function getIdFieldName()
251: {
252: return $this->getEntityIdField();
253: }
254:
255: 256: 257: 258: 259: 260:
261: public function getTable($alias)
262: {
263: return Mage::getSingleton('core/resource')->getTableName($alias);
264: }
265:
266: 267: 268: 269: 270: 271: 272: 273:
274: public function setType($type)
275: {
276: $this->_type = Mage::getSingleton('eav/config')->getEntityType($type);
277: $this->_afterSetConfig();
278: return $this;
279: }
280:
281: 282: 283: 284: 285:
286: public function getEntityType()
287: {
288: if (empty($this->_type)) {
289: throw Mage::exception('Mage_Eav', Mage::helper('eav')->__('Entity is not initialized'));
290: }
291: return $this->_type;
292: }
293:
294: 295: 296: 297: 298:
299: public function getType()
300: {
301: return $this->getEntityType()->getEntityTypeCode();
302: }
303:
304: 305: 306: 307: 308:
309: public function getTypeId()
310: {
311: return (int)$this->getEntityType()->getEntityTypeId();
312: }
313:
314: 315: 316: 317: 318: 319: 320: 321: 322:
323: public function unsetAttributes($attributes = null)
324: {
325: if ($attributes === null) {
326: $this->_attributesByCode = array();
327: $this->_attributesById = array();
328: $this->_attributesByTable = array();
329: return $this;
330: }
331:
332: if (is_string($attributes)) {
333: $attributes = array($attributes);
334: }
335:
336: if (!is_array($attributes)) {
337: throw Mage::exception('Mage_Eav', Mage::helper('eav')->__('Unknown parameter'));
338: }
339:
340: foreach ($attributes as $attrCode) {
341: if (!isset($this->_attributesByCode[$attrCode])) {
342: continue;
343: }
344:
345: $attr = $this->getAttribute($attrCode);
346: unset($this->_attributesById[$attr->getId()]);
347: unset($this->_attributesByTable[$attr->getBackend()->getTable()][$attrCode]);
348: unset($this->_attributesByCode[$attrCode]);
349: }
350:
351: return $this;
352: }
353:
354: 355: 356: 357: 358: 359: 360: 361: 362: 363:
364: public function getAttribute($attribute)
365: {
366: if (is_numeric($attribute)) {
367: $attributeId = $attribute;
368:
369: if (isset($this->_attributesById[$attributeId])) {
370: return $this->_attributesById[$attributeId];
371: }
372: $attributeInstance = Mage::getSingleton('eav/config')->getAttribute($this->getEntityType(), $attributeId);
373: if ($attributeInstance) {
374: $attributeCode = $attributeInstance->getAttributeCode();
375: }
376:
377: } else if (is_string($attribute)) {
378: $attributeCode = $attribute;
379:
380: if (isset($this->_attributesByCode[$attributeCode])) {
381: return $this->_attributesByCode[$attributeCode];
382: }
383: $attributeInstance = Mage::getSingleton('eav/config')
384: ->getAttribute($this->getEntityType(), $attributeCode);
385: if (!$attributeInstance->getAttributeCode() && in_array($attribute, $this->getDefaultAttributes())) {
386: $attributeInstance
387: ->setAttributeCode($attribute)
388: ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC)
389: ->setIsGlobal(1)
390: ->setEntity($this)
391: ->setEntityType($this->getEntityType())
392: ->setEntityTypeId($this->getEntityType()->getId());
393: }
394: } else if ($attribute instanceof Mage_Eav_Model_Entity_Attribute_Abstract) {
395:
396: $attributeInstance = $attribute;
397: $attributeCode = $attributeInstance->getAttributeCode();
398: if (isset($this->_attributesByCode[$attributeCode])) {
399: return $this->_attributesByCode[$attributeCode];
400: }
401: }
402:
403: if (empty($attributeInstance)
404: || !($attributeInstance instanceof Mage_Eav_Model_Entity_Attribute_Abstract)
405: || (!$attributeInstance->getId()
406: && !in_array($attributeInstance->getAttributeCode(), $this->getDefaultAttributes()))
407: ) {
408: return false;
409: }
410:
411: $attribute = $attributeInstance;
412:
413: if (empty($attributeId)) {
414: $attributeId = $attribute->getAttributeId();
415: }
416:
417: if (!$attribute->getAttributeCode()) {
418: $attribute->setAttributeCode($attributeCode);
419: }
420: if (!$attribute->getAttributeModel()) {
421: $attribute->setAttributeModel($this->_getDefaultAttributeModel());
422: }
423:
424: $this->addAttribute($attribute);
425:
426: return $attribute;
427: }
428:
429: 430: 431: 432: 433: 434:
435: protected function _getDefaultAttribute($attributeCode)
436: {
437: $entityTypeId = $this->getEntityType()->getId();
438: if (!isset(self::$_defaultAttributes[$entityTypeId][$attributeCode])) {
439: $attribute = Mage::getModel($this->getEntityType()->getAttributeModel())
440: ->setAttributeCode($attributeCode)
441: ->setBackendType(Mage_Eav_Model_Entity_Attribute_Abstract::TYPE_STATIC)
442: ->setIsGlobal(1)
443: ->setEntityType($this->getEntityType())
444: ->setEntityTypeId($this->getEntityType()->getId());
445: self::$_defaultAttributes[$entityTypeId][$attributeCode] = $attribute;
446: }
447:
448: return self::$_defaultAttributes[$entityTypeId][$attributeCode];
449: }
450:
451: 452: 453: 454: 455: 456:
457: public function addAttribute(Mage_Eav_Model_Entity_Attribute_Abstract $attribute)
458: {
459: $attribute->setEntity($this);
460: $attributeCode = $attribute->getAttributeCode();
461:
462: $this->_attributesByCode[$attributeCode] = $attribute;
463:
464: if ($attribute->isStatic()) {
465: $this->_staticAttributes[$attributeCode] = $attribute;
466: } else {
467: $this->_attributesById[$attribute->getId()] = $attribute;
468: $this->_attributesByTable[$attribute->getBackendTable()][$attributeCode] = $attribute;
469: }
470:
471: return $this;
472: }
473:
474: 475: 476: 477: 478: 479:
480: public function isPartialLoad($flag = null)
481: {
482: $result = $this->_isPartialLoad;
483: if ($flag !== null) {
484: $this->_isPartialLoad = (bool)$flag;
485: }
486: return $result;
487: }
488:
489: 490: 491: 492: 493: 494:
495: public function isPartialSave($flag = null)
496: {
497: $result = $this->_isPartialSave;
498: if ($flag !== null) {
499: $this->_isPartialSave = (bool)$flag;
500: }
501: return $result;
502: }
503:
504: 505: 506: 507: 508:
509: public function loadAllAttributes($object=null)
510: {
511: $attributeCodes = Mage::getSingleton('eav/config')
512: ->getEntityAttributeCodes($this->getEntityType(), $object);
513:
514: 515: 516:
517: $defaultAttributes = $this->getDefaultAttributes();
518: foreach ($defaultAttributes as $attributeCode) {
519: $attributeIndex = array_search($attributeCode, $attributeCodes);
520: if ($attributeIndex !== false) {
521: $this->getAttribute($attributeCodes[$attributeIndex]);
522: unset($attributeCodes[$attributeIndex]);
523: } else {
524: $this->addAttribute($this->_getDefaultAttribute($attributeCode));
525: }
526: }
527:
528: foreach ($attributeCodes as $code) {
529: $this->getAttribute($code);
530: }
531:
532: return $this;
533: }
534:
535: 536: 537: 538: 539: 540:
541: public function getSortedAttributes($setId = null)
542: {
543: $attributes = $this->getAttributesByCode();
544: if ($setId === null) {
545: $setId = $this->getEntityType()->getDefaultAttributeSetId();
546: }
547:
548:
549: Mage::getSingleton('eav/entity_attribute_set')
550: ->addSetInfo($this->getEntityType(), $attributes, $setId);
551:
552: foreach ($attributes as $code => $attribute) {
553:
554: if (!$attribute->isInSet($setId)) {
555: unset($attributes[$code]);
556: }
557: }
558:
559: $this->_sortingSetId = $setId;
560: uasort($attributes, array($this, 'attributesCompare'));
561: return $attributes;
562: }
563:
564: 565: 566: 567: 568: 569: 570:
571: public function attributesCompare($attribute1, $attribute2)
572: {
573: $sortPath = sprintf('attribute_set_info/%s/sort', $this->_sortingSetId);
574: $groupSortPath = sprintf('attribute_set_info/%s/group_sort', $this->_sortingSetId);
575:
576: $sort1 = ($attribute1->getData($groupSortPath) * 1000) + ($attribute1->getData($sortPath) * 0.0001);
577: $sort2 = ($attribute2->getData($groupSortPath) * 1000) + ($attribute2->getData($sortPath) * 0.0001);
578:
579: if ($sort1 > $sort2) {
580: return 1;
581: } elseif ($sort1 < $sort2) {
582: return -1;
583: }
584:
585: return 0;
586: }
587:
588: 589: 590: 591: 592: 593: 594:
595: protected function _isApplicableAttribute($object, $attribute)
596: {
597: return true;
598: }
599:
600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612:
613: public function walkAttributes($partMethod, array $args = array())
614: {
615: $methodArr = explode('/', $partMethod);
616: switch (sizeof($methodArr)) {
617: case 1:
618: $part = 'attribute';
619: $method = $methodArr[0];
620: break;
621:
622: case 2:
623: $part = $methodArr[0];
624: $method = $methodArr[1];
625: break;
626: }
627: $results = array();
628: foreach ($this->getAttributesByCode() as $attrCode => $attribute) {
629:
630: if (isset($args[0]) && is_object($args[0]) && !$this->_isApplicableAttribute($args[0], $attribute)) {
631: continue;
632: }
633:
634: switch ($part) {
635: case 'attribute':
636: $instance = $attribute;
637: break;
638:
639: case 'backend':
640: $instance = $attribute->getBackend();
641: break;
642:
643: case 'frontend':
644: $instance = $attribute->getFrontend();
645: break;
646:
647: case 'source':
648: $instance = $attribute->getSource();
649: break;
650: }
651:
652: if (!$this->_isCallableAttributeInstance($instance, $method, $args)) {
653: continue;
654: }
655:
656: try {
657: $results[$attrCode] = call_user_func_array(array($instance, $method), $args);
658: } catch (Mage_Eav_Model_Entity_Attribute_Exception $e) {
659: throw $e;
660: } catch (Exception $e) {
661: $e = Mage::getModel('eav/entity_attribute_exception', $e->getMessage());
662: $e->setAttributeCode($attrCode)->setPart($part);
663: throw $e;
664: }
665: }
666:
667: return $results;
668: }
669:
670: 671: 672: 673: 674: 675: 676: 677:
678: protected function _isCallableAttributeInstance($instance, $method, $args)
679: {
680: if (!is_object($instance) || !method_exists($instance, $method)) {
681: return false;
682: }
683:
684: return true;
685: }
686:
687: 688: 689: 690: 691:
692: public function getAttributesByCode()
693: {
694: return $this->_attributesByCode;
695: }
696:
697: 698: 699: 700: 701:
702: public function getAttributesById()
703: {
704: return $this->_attributesById;
705: }
706:
707: 708: 709: 710: 711:
712: public function getAttributesByTable()
713: {
714: return $this->_attributesByTable;
715: }
716:
717: 718: 719: 720: 721:
722: public function getEntityTable()
723: {
724: if (!$this->_entityTable) {
725: $table = $this->getEntityType()->getEntityTable();
726: if (!$table) {
727: $table = Mage_Eav_Model_Entity::DEFAULT_ENTITY_TABLE;
728: }
729: $this->_entityTable = Mage::getSingleton('core/resource')->getTableName($table);
730: }
731:
732: return $this->_entityTable;
733: }
734:
735: 736: 737: 738: 739:
740: public function getEntityIdField()
741: {
742: if (!$this->_entityIdField) {
743: $this->_entityIdField = $this->getEntityType()->getEntityIdField();
744: if (!$this->_entityIdField) {
745: $this->_entityIdField = Mage_Eav_Model_Entity::DEFAULT_ENTITY_ID_FIELD;
746: }
747: }
748:
749: return $this->_entityIdField;
750: }
751:
752: 753: 754: 755: 756:
757: public function getValueEntityIdField()
758: {
759: return $this->getEntityIdField();
760: }
761:
762: 763: 764: 765: 766:
767: public function getValueTablePrefix()
768: {
769: if (!$this->_valueTablePrefix) {
770: $prefix = (string)$this->getEntityType()->getValueTablePrefix();
771: if (!empty($prefix)) {
772: $this->_valueTablePrefix = $prefix;
773: 774: 775:
776:
777: } else {
778: $this->_valueTablePrefix = $this->getEntityTable();
779: }
780: }
781:
782: return $this->_valueTablePrefix;
783: }
784:
785: 786: 787: 788: 789:
790: public function getEntityTablePrefix()
791: {
792: if (empty($this->_entityTablePrefix)) {
793: $prefix = $this->getEntityType()->getEntityTablePrefix();
794: if (empty($prefix)) {
795: $prefix = $this->getEntityType()->getEntityTable();
796: if (empty($prefix)) {
797: $prefix = Mage_Eav_Model_Entity::DEFAULT_ENTITY_TABLE;
798: }
799: }
800: $this->_entityTablePrefix = $prefix;
801: }
802:
803: return $this->_entityTablePrefix;
804: }
805:
806: 807: 808: 809: 810: 811: 812:
813: public function isAttributeStatic($attribute)
814: {
815: $attrInstance = $this->getAttribute($attribute);
816: $attrBackendStatic = $attrInstance->getBackend()->isStatic();
817: return $attrInstance && $attrBackendStatic;
818: }
819:
820: 821: 822: 823: 824: 825: 826:
827: public function validate($object)
828: {
829: $this->loadAllAttributes($object);
830: $result = $this->walkAttributes('backend/validate', array($object));
831: $errors = array();
832: foreach ($result as $attributeCode => $error) {
833: if ($error === false) {
834: $errors[$attributeCode] = true;
835: } elseif (is_string($error)) {
836: $errors[$attributeCode] = $error;
837: }
838: }
839: if (!$errors) {
840: return true;
841: }
842:
843: return $errors;
844: }
845:
846: 847: 848: 849: 850: 851:
852: public function setNewIncrementId(Varien_Object $object)
853: {
854: if ($object->getIncrementId()) {
855: return $this;
856: }
857:
858: $incrementId = $this->getEntityType()->fetchNewIncrementId($object->getStoreId());
859:
860: if ($incrementId !== false) {
861: $object->setIncrementId($incrementId);
862: }
863:
864: return $this;
865: }
866:
867: 868: 869: 870: 871: 872: 873:
874: public function checkAttributeUniqueValue(Mage_Eav_Model_Entity_Attribute_Abstract $attribute, $object)
875: {
876: $adapter = $this->_getReadAdapter();
877: $select = $adapter->select();
878: if ($attribute->getBackend()->getType() === 'static') {
879: $value = $object->getData($attribute->getAttributeCode());
880: $bind = array(
881: 'entity_type_id' => $this->getTypeId(),
882: 'attribute_code' => trim($value)
883: );
884:
885: $select
886: ->from($this->getEntityTable(), $this->getEntityIdField())
887: ->where('entity_type_id = :entity_type_id')
888: ->where($attribute->getAttributeCode() . ' = :attribute_code');
889: } else {
890: $value = $object->getData($attribute->getAttributeCode());
891: if ($attribute->getBackend()->getType() == 'datetime') {
892: $date = new Zend_Date($value, Varien_Date::DATE_INTERNAL_FORMAT);
893: $value = $date->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
894: }
895: $bind = array(
896: 'entity_type_id' => $this->getTypeId(),
897: 'attribute_id' => $attribute->getId(),
898: 'value' => trim($value)
899: );
900: $select
901: ->from($attribute->getBackend()->getTable(), $attribute->getBackend()->getEntityIdField())
902: ->where('entity_type_id = :entity_type_id')
903: ->where('attribute_id = :attribute_id')
904: ->where('value = :value');
905: }
906: $data = $adapter->fetchCol($select, $bind);
907:
908: if ($object->getId()) {
909: if (isset($data[0])) {
910: return $data[0] == $object->getId();
911: }
912: return true;
913: }
914:
915: return !count($data);
916: }
917:
918: 919: 920: 921: 922:
923: public function getDefaultAttributeSourceModel()
924: {
925: return Mage_Eav_Model_Entity::DEFAULT_SOURCE_MODEL;
926: }
927:
928: 929: 930: 931: 932: 933: 934: 935:
936: public function load($object, $entityId, $attributes = array())
937: {
938: Varien_Profiler::start('__EAV_LOAD_MODEL__');
939: 940: 941:
942: $select = $this->_getLoadRowSelect($object, $entityId);
943: $row = $this->_getReadAdapter()->fetchRow($select);
944:
945: if (is_array($row)) {
946: $object->addData($row);
947: } else {
948: $object->isObjectNew(true);
949: }
950:
951: if (empty($attributes)) {
952: $this->loadAllAttributes($object);
953: } else {
954: foreach ($attributes as $attrCode) {
955: $this->getAttribute($attrCode);
956: }
957: }
958:
959: $this->_loadModelAttributes($object);
960:
961: $object->setOrigData();
962: Varien_Profiler::start('__EAV_LOAD_MODEL_AFTER_LOAD__');
963:
964: $this->_afterLoad($object);
965: Varien_Profiler::stop('__EAV_LOAD_MODEL_AFTER_LOAD__');
966:
967: Varien_Profiler::stop('__EAV_LOAD_MODEL__');
968: return $this;
969: }
970:
971: 972: 973: 974: 975: 976:
977: protected function _loadModelAttributes($object)
978: {
979: if (!$object->getId()) {
980: return $this;
981: }
982:
983: Varien_Profiler::start('__EAV_LOAD_MODEL_ATTRIBUTES__');
984:
985: $selects = array();
986: foreach (array_keys($this->getAttributesByTable()) as $table) {
987: $attribute = current($this->_attributesByTable[$table]);
988: $eavType = $attribute->getBackendType();
989: $select = $this->_getLoadAttributesSelect($object, $table);
990: $selects[$eavType][] = $this->_addLoadAttributesSelectFields($select, $table, $eavType);
991: }
992: $selectGroups = Mage::getResourceHelper('eav')->getLoadAttributesSelectGroups($selects);
993: foreach ($selectGroups as $selects) {
994: if (!empty($selects)) {
995: $select = $this->_prepareLoadSelect($selects);
996: $values = $this->_getReadAdapter()->fetchAll($select);
997: foreach ($values as $valueRow) {
998: $this->_setAttributeValue($object, $valueRow);
999: }
1000: }
1001: }
1002:
1003: Varien_Profiler::stop('__EAV_LOAD_MODEL_ATTRIBUTES__');
1004:
1005: return $this;
1006: }
1007:
1008: 1009: 1010: 1011: 1012: 1013:
1014: protected function _prepareLoadSelect(array $selects)
1015: {
1016: return $this->_getReadAdapter()->select()->union($selects, Zend_Db_Select::SQL_UNION_ALL);
1017: }
1018:
1019: 1020: 1021: 1022: 1023: 1024: 1025:
1026: protected function _getLoadRowSelect($object, $rowId)
1027: {
1028: $select = $this->_getReadAdapter()->select()
1029: ->from($this->getEntityTable())
1030: ->where($this->getEntityIdField() . ' =?', $rowId);
1031:
1032: return $select;
1033: }
1034:
1035: 1036: 1037: 1038: 1039: 1040: 1041:
1042: protected function _getLoadAttributesSelect($object, $table)
1043: {
1044: $select = $this->_getReadAdapter()->select()
1045: ->from($table, array())
1046: ->where($this->getEntityIdField() . ' =?', $object->getId());
1047:
1048: return $select;
1049: }
1050:
1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058:
1059: protected function _addLoadAttributesSelectFields($select, $table, $type)
1060: {
1061: $select->columns(
1062: Mage::getResourceHelper('eav')->attributeSelectFields($table, $type)
1063: );
1064: return $select;
1065: }
1066:
1067: 1068: 1069: 1070: 1071: 1072: 1073: 1074: 1075:
1076: protected function _setAttribteValue($object, $valueRow)
1077: {
1078: return _setAttributeValue($object, $valueRow);
1079: }
1080:
1081: 1082: 1083: 1084: 1085: 1086: 1087:
1088: protected function _setAttributeValue($object, $valueRow)
1089: {
1090: $attribute = $this->getAttribute($valueRow['attribute_id']);
1091: if ($attribute) {
1092: $attributeCode = $attribute->getAttributeCode();
1093: $object->setData($attributeCode, $valueRow['value']);
1094: $attribute->getBackend()->setEntityValueId($object, $valueRow['value_id']);
1095: }
1096:
1097: return $this;
1098: }
1099:
1100: 1101: 1102: 1103: 1104: 1105:
1106: public function save(Varien_Object $object)
1107: {
1108: if ($object->isDeleted()) {
1109: return $this->delete($object);
1110: }
1111:
1112: if (!$this->isPartialSave()) {
1113: $this->loadAllAttributes($object);
1114: }
1115:
1116: if (!$object->getEntityTypeId()) {
1117: $object->setEntityTypeId($this->getTypeId());
1118: }
1119:
1120: $object->setParentId((int) $object->getParentId());
1121:
1122: $this->_beforeSave($object);
1123: $this->_processSaveData($this->_collectSaveData($object));
1124: $this->_afterSave($object);
1125:
1126: return $this;
1127: }
1128:
1129: 1130: 1131: 1132: 1133: 1134:
1135: protected function _getOrigObject($object)
1136: {
1137: $className = get_class($object);
1138: $origObject = new $className();
1139: $origObject->setData(array());
1140: $this->load($origObject, $object->getData($this->getEntityIdField()));
1141:
1142: return $origObject;
1143: }
1144:
1145: 1146: 1147: 1148: 1149: 1150: 1151: 1152: 1153: 1154: 1155:
1156: protected function _collectSaveData($newObject)
1157: {
1158: $newData = $newObject->getData();
1159: $entityId = $newObject->getData($this->getEntityIdField());
1160:
1161:
1162: $entityRow = array();
1163: $insert = array();
1164: $update = array();
1165: $delete = array();
1166:
1167: if (!empty($entityId)) {
1168: $origData = $newObject->getOrigData();
1169: 1170: 1171:
1172: if (empty($origData)) {
1173: $origData = $this->_getOrigObject($newObject)->getOrigData();
1174: }
1175:
1176: 1177: 1178: 1179:
1180: foreach ($origData as $k => $v) {
1181: if (!array_key_exists($k, $newData)) {
1182: unset($origData[$k]);
1183: }
1184: }
1185: } else {
1186: $origData = array();
1187: }
1188:
1189: $staticFields = $this->_getWriteAdapter()->describeTable($this->getEntityTable());
1190: $staticFields = array_keys($staticFields);
1191: $attributeCodes = array_keys($this->_attributesByCode);
1192:
1193: foreach ($newData as $k => $v) {
1194: 1195: 1196:
1197: if (is_numeric($k) || is_array($v)) {
1198: continue;
1199: }
1200: 1201: 1202:
1203: if (!in_array($k, $staticFields) && !in_array($k, $attributeCodes)) {
1204: continue;
1205: }
1206:
1207: $attribute = $this->getAttribute($k);
1208: if (empty($attribute)) {
1209: continue;
1210: }
1211:
1212: $attrId = $attribute->getAttributeId();
1213:
1214: 1215: 1216:
1217: if ($this->isAttributeStatic($k)) {
1218: $entityRow[$k] = $this->_prepareStaticValue($k, $v);
1219: continue;
1220: }
1221:
1222: 1223: 1224:
1225: if ($this->_canUpdateAttribute($attribute, $v, $origData)) {
1226: if ($this->_isAttributeValueEmpty($attribute, $v)) {
1227: $delete[$attribute->getBackend()->getTable()][] = array(
1228: 'attribute_id' => $attrId,
1229: 'value_id' => $attribute->getBackend()->getEntityValueId($newObject)
1230: );
1231: } elseif ($v !== $origData[$k]) {
1232: $update[$attrId] = array(
1233: 'value_id' => $attribute->getBackend()->getEntityValueId($newObject),
1234: 'value' => $v,
1235: );
1236: }
1237: } else if (!$this->_isAttributeValueEmpty($attribute, $v)) {
1238: $insert[$attrId] = $v;
1239: }
1240: }
1241:
1242: $result = compact('newObject', 'entityRow', 'insert', 'update', 'delete');
1243: return $result;
1244: }
1245:
1246: 1247: 1248: 1249: 1250: 1251: 1252: 1253:
1254: protected function _canUpdateAttribute(Mage_Eav_Model_Entity_Attribute_Abstract $attribute, $v, array &$origData)
1255: {
1256: return array_key_exists($attribute->getAttributeCode(), $origData);
1257: }
1258:
1259: 1260: 1261: 1262: 1263: 1264:
1265: protected function _getStaticFieldProperties($field)
1266: {
1267: if (empty($this->_describeTable[$this->getEntityTable()])) {
1268: $this->_describeTable[$this->getEntityTable()] = $this->_getWriteAdapter()
1269: ->describeTable($this->getEntityTable());
1270: }
1271:
1272: if (isset($this->_describeTable[$this->getEntityTable()][$field])) {
1273: return $this->_describeTable[$this->getEntityTable()][$field];
1274: }
1275:
1276: return false;
1277: }
1278:
1279: 1280: 1281: 1282: 1283: 1284: 1285:
1286: protected function _prepareStaticValue($key, $value)
1287: {
1288: $fieldProp = $this->_getStaticFieldProperties($key);
1289:
1290: if (!$fieldProp) {
1291: return $value;
1292: }
1293:
1294: if ($fieldProp['DATA_TYPE'] == 'decimal') {
1295: $value = Mage::app()->getLocale()->getNumber($value);
1296: }
1297:
1298: return $value;
1299: }
1300:
1301: 1302: 1303: 1304: 1305: 1306:
1307: protected function _processSaveData($saveData)
1308: {
1309: extract($saveData);
1310: 1311: 1312: 1313: 1314: 1315: 1316: 1317: 1318: 1319: 1320:
1321: $adapter = $this->_getWriteAdapter();
1322: $insertEntity = true;
1323: $entityTable = $this->getEntityTable();
1324: $entityIdField = $this->getEntityIdField();
1325: $entityId = $newObject->getId();
1326:
1327: unset($entityRow[$entityIdField]);
1328: if (!empty($entityId) && is_numeric($entityId)) {
1329: $bind = array('entity_id' => $entityId);
1330: $select = $adapter->select()
1331: ->from($entityTable, $entityIdField)
1332: ->where("{$entityIdField} = :entity_id");
1333: $result = $adapter->fetchOne($select, $bind);
1334: if ($result) {
1335: $insertEntity = false;
1336: }
1337: } else {
1338: $entityId = null;
1339: }
1340:
1341: 1342: 1343:
1344: $entityObject = new Varien_Object($entityRow);
1345: $entityRow = $this->_prepareDataForTable($entityObject, $entityTable);
1346: if ($insertEntity) {
1347: if (!empty($entityId)) {
1348: $entityRow[$entityIdField] = $entityId;
1349: $adapter->insertForce($entityTable, $entityRow);
1350: } else {
1351: $adapter->insert($entityTable, $entityRow);
1352: $entityId = $adapter->lastInsertId($entityTable);
1353: }
1354: $newObject->setId($entityId);
1355: } else {
1356: $where = sprintf('%s=%d', $adapter->quoteIdentifier($entityIdField), $entityId);
1357: $adapter->update($entityTable, $entityRow, $where);
1358: }
1359:
1360: 1361: 1362:
1363: if (!empty($insert)) {
1364: foreach ($insert as $attributeId => $value) {
1365: $attribute = $this->getAttribute($attributeId);
1366: $this->_insertAttribute($newObject, $attribute, $value);
1367: }
1368: }
1369:
1370: 1371: 1372:
1373: if (!empty($update)) {
1374: foreach ($update as $attributeId => $v) {
1375: $attribute = $this->getAttribute($attributeId);
1376: $this->_updateAttribute($newObject, $attribute, $v['value_id'], $v['value']);
1377: }
1378: }
1379:
1380: 1381: 1382:
1383: if (!empty($delete)) {
1384: foreach ($delete as $table => $values) {
1385: $this->_deleteAttributes($newObject, $table, $values);
1386: }
1387: }
1388:
1389: $this->_processAttributeValues();
1390:
1391: $newObject->isObjectNew(false);
1392:
1393: return $this;
1394: }
1395:
1396: 1397: 1398: 1399: 1400: 1401: 1402: 1403:
1404: protected function _insertAttribute($object, $attribute, $value)
1405: {
1406: return $this->_saveAttribute($object, $attribute, $value);
1407: }
1408:
1409: 1410: 1411: 1412: 1413: 1414: 1415: 1416: 1417:
1418: protected function _updateAttribute($object, $attribute, $valueId, $value)
1419: {
1420: return $this->_saveAttribute($object, $attribute, $value);
1421: }
1422:
1423: 1424: 1425: 1426: 1427: 1428: 1429: 1430: 1431: 1432:
1433: protected function _saveAttribute($object, $attribute, $value)
1434: {
1435: $table = $attribute->getBackend()->getTable();
1436: if (!isset($this->_attributeValuesToSave[$table])) {
1437: $this->_attributeValuesToSave[$table] = array();
1438: }
1439:
1440: $entityIdField = $attribute->getBackend()->getEntityIdField();
1441:
1442: $data = array(
1443: 'entity_type_id' => $object->getEntityTypeId(),
1444: $entityIdField => $object->getId(),
1445: 'attribute_id' => $attribute->getId(),
1446: 'value' => $this->_prepareValueForSave($value, $attribute)
1447: );
1448:
1449: $this->_attributeValuesToSave[$table][] = $data;
1450:
1451: return $this;
1452: }
1453:
1454: 1455: 1456: 1457: 1458:
1459: protected function _processAttributeValues()
1460: {
1461: $adapter = $this->_getWriteAdapter();
1462: foreach ($this->_attributeValuesToSave as $table => $data) {
1463: $adapter->insertOnDuplicate($table, $data, array('value'));
1464: }
1465:
1466: foreach ($this->_attributeValuesToDelete as $table => $valueIds) {
1467: $adapter->delete($table, array('value_id IN (?)' => $valueIds));
1468: }
1469:
1470:
1471: $this->_attributeValuesToSave = array();
1472: $this->_attributeValuesToDelete = array();
1473:
1474: return $this;
1475: }
1476:
1477: 1478: 1479: 1480: 1481: 1482: 1483:
1484: protected function _prepareValueForSave($value, Mage_Eav_Model_Entity_Attribute_Abstract $attribute)
1485: {
1486: if ($attribute->getBackendType() == 'decimal') {
1487: return Mage::app()->getLocale()->getNumber($value);
1488: }
1489:
1490: $backendTable = $attribute->getBackendTable();
1491: if (!isset(self::$_attributeBackendTables[$backendTable])) {
1492: self::$_attributeBackendTables[$backendTable] = $this->_getReadAdapter()->describeTable($backendTable);
1493: }
1494: $describe = self::$_attributeBackendTables[$backendTable];
1495: return $this->_getReadAdapter()->prepareColumnValue($describe['value'], $value);
1496: }
1497:
1498: 1499: 1500: 1501: 1502: 1503: 1504: 1505:
1506: protected function _deleteAttributes($object, $table, $info)
1507: {
1508: $valueIds = array();
1509: foreach ($info as $itemData) {
1510: $valueIds[] = $itemData['value_id'];
1511: }
1512:
1513: if (empty($valueIds)) {
1514: return $this;
1515: }
1516:
1517: if (isset($this->_attributeValuesToDelete[$table])) {
1518: $this->_attributeValuesToDelete[$table] = array_merge($this->_attributeValuesToDelete[$table], $valueIds);
1519: } else {
1520: $this->_attributeValuesToDelete[$table] = $valueIds;
1521: }
1522:
1523: return $this;
1524: }
1525:
1526: 1527: 1528: 1529: 1530: 1531: 1532:
1533: public function saveAttribute(Varien_Object $object, $attributeCode)
1534: {
1535: $attribute = $this->getAttribute($attributeCode);
1536: $backend = $attribute->getBackend();
1537: $table = $backend->getTable();
1538: $entity = $attribute->getEntity();
1539: $entityIdField = $entity->getEntityIdField();
1540: $adapter = $this->_getWriteAdapter();
1541:
1542: $row = array(
1543: 'entity_type_id' => $entity->getTypeId(),
1544: 'attribute_id' => $attribute->getId(),
1545: $entityIdField => $object->getData($entityIdField),
1546: );
1547:
1548: $newValue = $object->getData($attributeCode);
1549: if ($attribute->isValueEmpty($newValue)) {
1550: $newValue = null;
1551: }
1552:
1553: $whereArr = array();
1554: foreach ($row as $field => $value) {
1555: $whereArr[] = $adapter->quoteInto($field . '=?', $value);
1556: }
1557: $where = implode(' AND ', $whereArr);
1558:
1559: $adapter->beginTransaction();
1560:
1561: try {
1562: $select = $adapter->select()
1563: ->from($table, 'value_id')
1564: ->where($where);
1565: $origValueId = $adapter->fetchOne($select);
1566:
1567: if ($origValueId === false && ($newValue !== null)) {
1568: $this->_insertAttribute($object, $attribute, $newValue);
1569: } elseif ($origValueId !== false && ($newValue !== null)) {
1570: $this->_updateAttribute($object, $attribute, $origValueId, $newValue);
1571: } elseif ($origValueId !== false && ($newValue === null)) {
1572: $adapter->delete($table, $where);
1573: }
1574: $this->_processAttributeValues();
1575: $adapter->commit();
1576: } catch (Exception $e) {
1577: $adapter->rollback();
1578: throw $e;
1579: }
1580:
1581: return $this;
1582: }
1583:
1584: 1585: 1586: 1587: 1588:
1589: public function delete($object)
1590: {
1591: if (is_numeric($object)) {
1592: $id = (int)$object;
1593: } elseif ($object instanceof Varien_Object) {
1594: $id = (int)$object->getId();
1595: }
1596:
1597: $this->_beforeDelete($object);
1598:
1599: try {
1600: $where = array(
1601: $this->getEntityIdField() . '=?' => $id
1602: );
1603: $this->_getWriteAdapter()->delete($this->getEntityTable(), $where);
1604: $this->loadAllAttributes($object);
1605: foreach ($this->getAttributesByTable() as $table => $attributes) {
1606: $this->_getWriteAdapter()->delete($table, $where);
1607: }
1608: } catch (Exception $e) {
1609: throw $e;
1610: }
1611:
1612: $this->_afterDelete($object);
1613: return $this;
1614: }
1615:
1616: 1617: 1618: 1619: 1620: 1621:
1622: protected function _afterLoad(Varien_Object $object)
1623: {
1624: $this->walkAttributes('backend/afterLoad', array($object));
1625: return $this;
1626: }
1627:
1628: 1629: 1630: 1631: 1632: 1633:
1634: protected function _beforeSave(Varien_Object $object)
1635: {
1636: $this->walkAttributes('backend/beforeSave', array($object));
1637: return $this;
1638: }
1639:
1640: 1641: 1642: 1643: 1644: 1645:
1646: protected function _afterSave(Varien_Object $object)
1647: {
1648: $this->walkAttributes('backend/afterSave', array($object));
1649: return $this;
1650: }
1651:
1652: 1653: 1654: 1655: 1656: 1657:
1658: protected function _beforeDelete(Varien_Object $object)
1659: {
1660: $this->walkAttributes('backend/beforeDelete', array($object));
1661: return $this;
1662: }
1663:
1664: 1665: 1666: 1667: 1668: 1669:
1670: protected function _afterDelete(Varien_Object $object)
1671: {
1672: $this->walkAttributes('backend/afterDelete', array($object));
1673: return $this;
1674: }
1675:
1676: 1677: 1678: 1679: 1680:
1681: protected function _getDefaultAttributeModel()
1682: {
1683: return Mage_Eav_Model_Entity::DEFAULT_ATTRIBUTE_MODEL;
1684: }
1685:
1686: 1687: 1688: 1689: 1690:
1691: protected function _getDefaultAttributes()
1692: {
1693: return array('entity_type_id', 'attribute_set_id', 'created_at', 'updated_at', 'parent_id', 'increment_id');
1694: }
1695:
1696: 1697: 1698: 1699: 1700:
1701: public function getDefaultAttributes() {
1702: return array_unique(array_merge($this->_getDefaultAttributes(), array($this->getEntityIdField())));
1703: }
1704:
1705: 1706: 1707: 1708: 1709: 1710:
1711: protected function _afterSetConfig()
1712: {
1713: return $this;
1714: }
1715:
1716: 1717: 1718: 1719: 1720: 1721: 1722:
1723: protected function _isAttributeValueEmpty(Mage_Eav_Model_Entity_Attribute_Abstract $attribute, $value)
1724: {
1725: return $attribute->isValueEmpty($value);
1726: }
1727: }
1728: