00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 class Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Flat_Indexer
00036 extends Mage_Core_Model_Mysql4_Abstract
00037 {
00038 const XML_NODE_MAX_INDEX_COUNT = 'global/catalog/product/flat/max_index_count';
00039 const XML_NODE_ATTRIBUTE_NODES = 'global/catalog/product/flat/attribute_nodes';
00040
00041
00042
00043
00044
00045
00046 protected $_attributeCodes;
00047
00048
00049
00050
00051
00052
00053 protected $_attributes;
00054
00055
00056
00057
00058
00059
00060 protected $_systemAttributes = array('status', 'required_options', 'tax_class_id', 'weight');
00061
00062
00063
00064
00065
00066
00067 protected $_entityTypeId;
00068
00069
00070
00071
00072
00073
00074 protected $_columns;
00075
00076
00077
00078
00079
00080
00081 protected $_indexes;
00082
00083
00084
00085
00086
00087
00088 protected $_productTypes;
00089
00090
00091
00092
00093
00094 protected function _construct()
00095 {
00096 $this->_init('catalog/product', 'entity_id');
00097 }
00098
00099
00100
00101
00102
00103
00104 public function rebuild($store = null)
00105 {
00106 if (is_null($store)) {
00107 foreach (Mage::app()->getStores() as $store) {
00108 $this->rebuild($store->getId());
00109 }
00110 $flag = $this->getFlatHelper()->getFlag();
00111 $flag->setIsBuild(true)->save();
00112 return $this;
00113 }
00114
00115 $this->prepareFlatTable($store);
00116 $this->cleanNonWebsiteProducts($store);
00117 $this->updateStaticAttributes($store);
00118 $this->updateEavAttributes($store);
00119 $this->updateEventAttributes($store);
00120 $this->updateRelationProducts($store);
00121 $this->cleanRelationProducts($store);
00122
00123 return $this;
00124 }
00125
00126
00127
00128
00129
00130
00131 public function getFlatHelper()
00132 {
00133 return Mage::helper('catalog/product_flat');
00134 }
00135
00136
00137
00138
00139
00140
00141 public function getAttributeCodes()
00142 {
00143 if (is_null($this->_attributeCodes)) {
00144 $attributeNodes = Mage::getConfig()
00145 ->getNode(self::XML_NODE_ATTRIBUTE_NODES)
00146 ->children();
00147 foreach ($attributeNodes as $node) {
00148 $attributes = Mage::getConfig()->getNode((string)$node)->asArray();
00149 $attributes = array_keys($attributes);
00150 $this->_systemAttributes = array_unique(array_merge($attributes, $this->_systemAttributes));
00151 }
00152
00153 $this->_attributeCodes = array();
00154 $whereCond = array(
00155 $this->_getReadAdapter()->quoteInto('backend_type=?', 'static'),
00156 $this->_getReadAdapter()->quoteInto('used_in_product_listing=?', 1),
00157 $this->_getReadAdapter()->quoteInto('used_for_sort_by=?', 1),
00158 $this->_getReadAdapter()->quoteInto('attribute_code IN(?)', $this->_systemAttributes)
00159 );
00160 if ($this->getFlatHelper()->isAddFilterableAttributes()) {
00161 $whereCond[] = $this->_getReadAdapter()->quoteInto('is_filterable>?', 0);
00162 }
00163
00164 $select = $this->_getReadAdapter()->select()
00165 ->from($this->getTable('eav/attribute'))
00166 ->where('entity_type_id=?', $this->getEntityTypeId())
00167 ->where(join(' OR ', $whereCond));
00168 $attributesData = $this->_getReadAdapter()->fetchAll($select);
00169 Mage::getSingleton('eav/config')
00170 ->importAttributesData($this->getEntityType(), $attributesData);
00171 $this->_attributeCodes = array();
00172 foreach ($attributesData as $data) {
00173 $this->_attributeCodes[$data['attribute_id']] = $data['attribute_code'];
00174 }
00175 unset($attributesData);
00176 }
00177 return $this->_attributeCodes;
00178 }
00179
00180
00181
00182
00183
00184
00185 public function getEntityType()
00186 {
00187 return 'catalog_product';
00188 }
00189
00190
00191
00192
00193
00194
00195 public function getEntityTypeId()
00196 {
00197 if (is_null($this->_entityTypeId)) {
00198 $this->_entityTypeId = Mage::getResourceModel('catalog/config')
00199 ->getEntityTypeId();
00200 }
00201 return $this->_entityTypeId;
00202 }
00203
00204
00205
00206
00207
00208
00209
00210 public function getAttributes()
00211 {
00212 if (is_null($this->_attributes)) {
00213 $attributeCodes = $this->getAttributeCodes(false);
00214 $entity = Mage::getSingleton('eav/config')
00215 ->getEntityType($this->getEntityType())
00216 ->getEntity();
00217 foreach ($attributeCodes as $attributeCode) {
00218 $attribute = Mage::getSingleton('eav/config')
00219 ->getAttribute($this->getEntityType(), $attributeCode)
00220 ->setEntity($entity);
00221 $this->_attributes[$attributeCode] = $attribute;
00222 }
00223 }
00224 return $this->_attributes;
00225 }
00226
00227
00228
00229
00230
00231
00232
00233 public function getAttribute($attributeCode)
00234 {
00235 $attributes = $this->getAttributes();
00236 if (!isset($attributes[$attributeCode])) {
00237 $attribute = Mage::getModel('catalog/resource_eav_attribute')
00238 ->loadByCode($this->getEntityTypeId(), $attributeCode);
00239 if (!$attribute->getId()) {
00240 Mage::throwException(Mage::helper('catalog')->__('Invalid attribute %s', $attributeCode));
00241 }
00242 $entity = Mage::getSingleton('eav/config')
00243 ->getEntityType($this->getEntityType())
00244 ->getEntity();
00245 $attribute->setEntity($entity);
00246 return $attribute;
00247 }
00248 return $attributes[$attributeCode];
00249 }
00250
00251
00252
00253
00254
00255
00256
00257 public function getFlatTableName($store)
00258 {
00259 return $this->getTable('catalog/product_flat') . '_' . $store;
00260 }
00261
00262
00263
00264
00265
00266
00267 public function getFlatColumns()
00268 {
00269 if (is_null($this->_columns)) {
00270 $this->_columns = array();
00271 $this->_columns['entity_id'] = array(
00272 'type' => 'int(10)',
00273 'unsigned' => true,
00274 'is_null' => false,
00275 'default' => null,
00276 'extra' => 'auto_increment'
00277 );
00278 if ($this->getFlatHelper()->isAddChildData()) {
00279 $this->_columns['child_id'] = array(
00280 'type' => 'int(10)',
00281 'unsigned' => true,
00282 'is_null' => true,
00283 'default' => null,
00284 'extra' => null
00285 );
00286 $this->_columns['is_child'] = array(
00287 'type' => 'tinyint(1)',
00288 'unsigned' => true,
00289 'is_null' => false,
00290 'default' => 0,
00291 'extra' => null
00292 );
00293 }
00294 $this->_columns['attribute_set_id'] = array(
00295 'type' => 'smallint(5)',
00296 'unsigned' => true,
00297 'is_null' => false,
00298 'default' => 0,
00299 'extra' => null
00300 );
00301 $this->_columns['type_id'] = array(
00302 'type' => 'varchar(32)',
00303 'unsigned' => false,
00304 'is_null' => false,
00305 'default' => 'simple',
00306 'extra' => null
00307 );
00308
00309 foreach ($this->getAttributes() as $attribute) {
00310
00311 $columns = $attribute
00312 ->setFlatAddFilterableAttributes($this->getFlatHelper()->isAddFilterableAttributes())
00313 ->setFlatAddChildData($this->getFlatHelper()->isAddChildData())
00314 ->getFlatColumns();
00315 if (is_null($columns)) {
00316 continue;
00317 }
00318
00319 $this->_columns = array_merge($this->_columns, $columns);
00320 }
00321
00322 $columnsObject = new Varien_Object();
00323 $columnsObject->setColumns($this->_columns);
00324 Mage::dispatchEvent('catalog_product_flat_prepare_columns', array(
00325 'columns' => $columnsObject
00326 ));
00327 $this->_columns = $columnsObject->getColumns();
00328 }
00329 return $this->_columns;
00330 }
00331
00332
00333
00334
00335
00336
00337 public function getFlatIndexes()
00338 {
00339 if (is_null($this->_indexes)) {
00340 $this->_indexes = array();
00341
00342 if ($this->getFlatHelper()->isAddChildData()) {
00343 $this->_indexes['PRIMARY'] = array(
00344 'type' => 'primary',
00345 'fields' => array('entity_id', 'child_id')
00346 );
00347 $this->_indexes['IDX_CHILD'] = array(
00348 'type' => 'index',
00349 'fields' => array('child_id')
00350 );
00351 $this->_indexes['IDX_IS_CHILD'] = array(
00352 'type' => 'index',
00353 'fields' => array('entity_id', 'is_child')
00354 );
00355 }
00356 else {
00357 $this->_indexes['PRIMARY'] = array(
00358 'type' => 'primary',
00359 'fields' => array('entity_id')
00360 );
00361 }
00362 $this->_indexes['IDX_TYPE_ID'] = array(
00363 'type' => 'index',
00364 'fields' => array('type_id')
00365 );
00366 $this->_indexes['IDX_ATRRIBUTE_SET'] = array(
00367 'type' => 'index',
00368 'fields' => array('attribute_set_id')
00369 );
00370
00371 foreach ($this->getAttributes() as $attribute) {
00372
00373 $indexes = $attribute
00374 ->setFlatAddFilterableAttributes($this->getFlatHelper()->isAddFilterableAttributes())
00375 ->setFlatAddChildData($this->getFlatHelper()->isAddChildData())
00376 ->getFlatIndexes();
00377 if (is_null($indexes)) {
00378 continue;
00379 }
00380 $this->_indexes = array_merge($this->_indexes, $indexes);
00381 }
00382
00383 $indexesObject = new Varien_Object();
00384 $indexesObject->setIndexes($this->_indexes);
00385 Mage::dispatchEvent('catalog_product_flat_prepare_indexes', array(
00386 'indexes' => $indexesObject
00387 ));
00388 $this->_indexes = $indexesObject->getIndexes();
00389 }
00390 return $this->_indexes;
00391 }
00392
00393
00394
00395
00396
00397
00398
00399 public function prepareFlatTable($store)
00400 {
00401 $columns = $this->getFlatColumns();
00402 $indexes = $this->getFlatIndexes();
00403
00404 $maxIndex = Mage::getConfig()->getNode(self::XML_NODE_MAX_INDEX_COUNT);
00405
00406 if (count($indexes) > $maxIndex) {
00407 Mage::throwException(Mage::helper('catalog')->__("Flat Catalog module has a limit of %2\$d filterable and/or sort able attributes. Currently there are %1\$d. Please reduce the number of filterable/sort able attributes in order to use this module.", count($indexes), $maxIndex));
00408 }
00409
00410 $tableName = $this->getFlatTableName($store);
00411 $tableNameQuote = $this->_getWriteAdapter()->quoteIdentifier($tableName);
00412 $tableExistsSql = $this->_getWriteAdapter()
00413 ->quoteInto("SHOW TABLE STATUS LIKE ?", $tableName);
00414 if (!$this->_getWriteAdapter()->fetchRow($tableExistsSql)) {
00415 $sql = "CREATE TABLE {$tableNameQuote} (\n";
00416 foreach ($columns as $field => $fieldProp) {
00417 $fieldNameQuote = $this->_getWriteAdapter()->quoteIdentifier($field);
00418 $sql .= " {$fieldNameQuote} {$fieldProp['type']}";
00419 $sql .= ($fieldProp['unsigned'] ? ' UNSIGNED' : '');
00420 $sql .= ($fieldProp['extra'] ? ' ' . $fieldProp['extra'] : '');
00421 $sql .= ($fieldProp['is_null'] === false ? ' NOT NULL' : '');
00422 $sql .= ($fieldProp['default'] === null
00423 ? ' DEFAULT NULL'
00424 : $this->_getReadAdapter()->quoteInto(' DEFAULT ?', $fieldProp['default']));
00425 $sql .= ",\n";
00426 }
00427 foreach ($indexes as $indexName => $indexProp) {
00428 $fields = $indexProp['fields'];
00429 if (is_array($fields)) {
00430 $fieldSql = array();
00431 foreach ($fields as $field) {
00432 $fieldSql[] = $this->_getReadAdapter()->quoteIdentifier($field);
00433 }
00434 $fieldSql = join(',', $fieldSql);
00435 }
00436 else {
00437 $fieldSql = $this->_getReadAdapter()->quoteIdentifier($fields);
00438 }
00439
00440 switch (strtolower($indexProp['type'])) {
00441 case 'primary':
00442 $condition = 'PRIMARY KEY';
00443 break;
00444 case 'unique':
00445 $condition = 'UNIQUE ' . $this->_getReadAdapter()->quoteIdentifier($indexName);
00446 break;
00447 case 'fulltext':
00448 $condition = 'FULLTEXT ' . $this->_getReadAdapter()->quoteIdentifier($indexName);
00449 break;
00450 default:
00451 $condition = 'KEY ' . $this->_getReadAdapter()->quoteIdentifier($indexName);
00452 break;
00453 }
00454
00455 $sql .= " {$condition} (" . $fieldSql . "),\n";
00456 }
00457
00458 $sql .= " CONSTRAINT `FK_CATALOG_PRODUCT_FLAT_{$store}_ENTITY` FOREIGN KEY (`entity_id`)"
00459 . " REFERENCES `{$this->getTable('catalog/product')}` (`entity_id`) ON DELETE CASCADE ON UPDATE CASCADE";
00460 if ($this->getFlatHelper()->isAddChildData()) {
00461 $sql .= ",\n CONSTRAINT `FK_CATALOG_PRODUCT_FLAT_{$store}_CHILD` FOREIGN KEY (`child_id`)"
00462 . " REFERENCES `{$this->getTable('catalog/product')}` (`entity_id`) ON DELETE CASCADE ON UPDATE CASCADE";
00463 }
00464 $sql .= "\n) ENGINE=InnoDB DEFAULT CHARSET=utf8";
00465 $this->_getWriteAdapter()->query($sql);
00466 }
00467 else {
00468 $describe = $this->_getWriteAdapter()->describeTable($tableName);
00469 $indexList = $this->_getWriteAdapter()->getIndexList($tableName);
00470
00471 $addColumns = array_diff_key($columns, $describe);
00472 $dropColumns = array_diff_key($describe, $columns);
00473
00474 $addIndexes = array_diff_key($indexes, $indexList);
00475 $dropIndexes = array_diff_key($indexList, $indexes);
00476 $addConstraints = array();
00477
00478 if (!$this->getFlatHelper()->isAddChildData() && isset($describe['is_child'])) {
00479 $this->_getWriteAdapter()->delete($tableName, 'is_child=1');
00480 $this->_getWriteAdapter()->dropForeignKey($tableName, "FK_CATALOG_PRODUCT_FLAT_{$store}_CHILD");
00481 }
00482 if ($this->getFlatHelper()->isAddChildData() && !isset($describe['is_child'])) {
00483 $this->_getWriteAdapter()->truncate($tableName);
00484 $dropIndexes['PRIMARY'] = $indexList['PRIMARY'];
00485 $addIndexes['PRIMARY'] = $indexes['PRIMARY'];
00486 $addConstraints["FK_CATALOG_PRODUCT_FLAT_{$store}_CHILD"] = array(
00487 'table_index' => 'child_id',
00488 'ref_table' => $this->getTable('catalog/product'),
00489 'ref_index' => 'entity_id',
00490 'on_update' => 'CASCADE',
00491 'on_delete' => 'CASCADE'
00492 );
00493 }
00494
00495 foreach ($indexList as $indexName => $indexProp) {
00496 if (isset($indexes[$indexName]) && ($indexes[$indexName]['type'] != $indexProp['type'])) {
00497 $dropIndexes[$indexName] = $indexProp;
00498 $addIndexes[$indexName] = $indexes[$indexName];
00499 }
00500 }
00501
00502 if ($addColumns or $dropColumns or $addIndexes or $dropIndexes) {
00503 $sql = "ALTER TABLE {$tableNameQuote}";
00504
00505 foreach ($dropColumns as $columnName => $columnProp) {
00506 $columnNameQuote = $this->_getWriteAdapter()->quoteIdentifier($columnName);
00507 $sql .= " DROP COLUMN {$columnNameQuote},";
00508 }
00509
00510 foreach ($dropIndexes as $indexName => $indexProp) {
00511 if ($indexName == 'PRIMARY') {
00512 $sql .= " DROP PRIMARY KEY,";
00513 }
00514 else {
00515 $indexNameQuote = $this->_getWriteAdapter()->quoteIdentifier($indexName);
00516 $sql .= " DROP INDEX {$indexNameQuote},";
00517 }
00518 }
00519
00520
00521 foreach ($addColumns as $columnName => $columnProp) {
00522
00523 $columnNameQuote = $this->_getWriteAdapter()->quoteIdentifier($columnName);
00524 $sql .= " ADD COLUMN {$columnNameQuote} {$columnProp['type']}";
00525 $sql .= ($columnProp['unsigned'] ? ' UNSIGNED' : '');
00526 $sql .= ($columnProp['extra'] ? ' ' . $columnProp['extra'] : '');
00527 $sql .= ($columnProp['is_null'] === false ? ' NOT NULL' : '');
00528 $sql .= ($columnProp['default'] === null
00529 ? ' DEFAULT NULL'
00530 : $this->_getReadAdapter()->quoteInto(' DEFAULT ?', $columnProp['default']));
00531 if ($afterField = $this->_arrayPrevKey($columns, $columnName)) {
00532 $sql .= ' AFTER ' . $this->_getWriteAdapter()->quoteIdentifier($afterField);
00533 }
00534 $sql .= ",";
00535 }
00536
00537 foreach ($addIndexes as $indexName => $indexProp) {
00538 $indexNameQuote = $this->_getWriteAdapter()->quoteIdentifier($indexName);
00539
00540 switch (strtolower($indexProp['type'])) {
00541 case 'primary':
00542 $condition = 'PRIMARY KEY';
00543 break;
00544 case 'unique':
00545 $condition = 'UNIQUE ' . $indexNameQuote;
00546 break;
00547 case 'fulltext':
00548 $condition = 'FULLTEXT ' . $indexNameQuote;
00549 break;
00550 default:
00551 $condition = 'INDEX ' . $indexNameQuote;
00552 break;
00553 }
00554
00555 $fields = $indexProp['fields'];
00556 if (is_array($fields)) {
00557 $fieldSql = array();
00558 foreach ($fields as $field) {
00559 $fieldSql[] = $this->_getReadAdapter()->quoteIdentifier($field);
00560 }
00561 $fieldSql = join(',', $fieldSql);
00562 }
00563 else {
00564 $fieldSql = $this->_getReadAdapter()->quoteIdentifier($fields);
00565 }
00566
00567 $sql .= " ADD {$condition} ({$fieldSql}),";
00568 }
00569 $sql = rtrim($sql, ",");
00570 $this->_getWriteAdapter()->query($sql);
00571 }
00572
00573 foreach ($addConstraints as $constraintName => $constraintProp) {
00574 $this->_getWriteAdapter()->addConstraint(
00575 $constraintName,
00576 $tableName,
00577 $constraintProp['table_index'],
00578 $constraintProp['ref_table'],
00579 $constraintProp['ref_index'],
00580 $constraintProp['on_delete'],
00581 $constraintProp['on_update']
00582 );
00583 }
00584 }
00585
00586 return $this;
00587 }
00588
00589
00590
00591
00592
00593
00594
00595
00596 public function updateStaticAttributes($store, $productIds = null)
00597 {
00598 $website = Mage::app()->getStore($store)->getWebsite()->getId();
00599 $status = $this->getAttribute('status');
00600
00601 $fieldList = array('entity_id', 'type_id', 'attribute_set_id');
00602 $colsList = array('entity_id', 'type_id', 'attribute_set_id');
00603 if ($this->getFlatHelper()->isAddChildData()) {
00604 $fieldList = array_merge($fieldList, array('child_id', 'is_child'));
00605 $isChild = new Zend_Db_Expr('0');
00606 $colsList = array_merge($colsList, array('entity_id', $isChild));
00607 }
00608
00609 $columns = $this->getFlatColumns();
00610 $select = $this->_getWriteAdapter()->select()
00611 ->from(
00612 array('e' => $this->getTable('catalog/product')),
00613 $colsList)
00614 ->join(
00615 array('wp' => $this->getTable('catalog/product_website')),
00616 "`e`.`entity_id`=`wp`.`product_id` AND `wp`.`website_id`={$website}",
00617 array())
00618 ->joinLeft(
00619 array('t1' => $status->getBackend()->getTable()),
00620 "`e`.`entity_id`=`t1`.`entity_id`",
00621 array())
00622 ->joinLeft(
00623 array('t2' => $status->getBackend()->getTable()),
00624 "t2.entity_id = t1.entity_id"
00625 . " AND t1.entity_type_id = t2.entity_type_id"
00626 . " AND t1.attribute_id = t2.attribute_id"
00627 . " AND t2.store_id = {$store}",
00628 array())
00629 ->where("t1.entity_type_id=?", $status->getEntityTypeId())
00630 ->where("t1.attribute_id=?", $status->getId())
00631 ->where("t1.store_id=?", 0)
00632 ->where("IFNULL(`t2`.`value`, `t1`.`value`)=?", Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
00633 foreach ($this->getAttributes() as $attributeCode => $attribute) {
00634
00635 if ($attribute->getBackend()->getType() == 'static') {
00636 if (!isset($columns[$attributeCode])) {
00637 continue;
00638 }
00639 $fieldList[] = $attributeCode;
00640 $select->from(null, $attributeCode);
00641 }
00642 }
00643
00644 if (!is_null($productIds)) {
00645 $select->where('e.entity_id IN(?)', $productIds);
00646 }
00647
00648 $sql = $select->insertFromSelect($this->getFlatTableName($store), $fieldList);
00649 $this->_getWriteAdapter()->query($sql);
00650 return $this;
00651 }
00652
00653
00654
00655
00656
00657
00658
00659
00660 public function cleanNonWebsiteProducts($store, $productIds = null)
00661 {
00662 $website = Mage::app()->getStore($store)->getWebsite()->getId();
00663
00664 $joinCond = "`e`.`entity_id`=`wp`.`product_id` AND `wp`.`website_id`={$website}";
00665 if ($this->getFlatHelper()->isAddChildData()) {
00666 $joinCond .= " AND `e`.`child_id`=`wp`.`product_id`";
00667 }
00668
00669 $select = $this->_getWriteAdapter()->select()
00670 ->from(
00671 array('e' => $this->getFlatTableName($store)),
00672 null)
00673 ->joinLeft(
00674 array('wp' => $this->getTable('catalog/product_website')),
00675 $joinCond,
00676 array());
00677 if (!is_null($productIds)) {
00678 $cond = array(
00679 $this->_getWriteAdapter()->quoteInto('e.entity_id IN(?)', $productIds)
00680 );
00681 if ($this->getFlatHelper()->isAddChildData()) {
00682 $cond[] = $this->_getWriteAdapter()->quoteInto('e.child_id IN(?)', $productIds);
00683 }
00684 $select->where(join(' OR ', $cond));
00685 }
00686
00687 $sql = $select->deleteFromSelect('e');
00688 $this->_getWriteAdapter()->query($sql);
00689
00690 return $this;
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701 public function updateAttribute($attribute, $store, $productIds = null)
00702 {
00703 if ($attribute->getBackend()->getType() == 'static') {
00704 $select = $this->_getWriteAdapter()->select()
00705 ->join(
00706 array('main_table' => $this->getTable('catalog/product')),
00707 'main_table.entity_id=e.entity_id ',
00708 array($attribute->getAttributeCode() => 'main_table.' . $attribute->getAttributeCode())
00709 );
00710 if ($this->getFlatHelper()->isAddChildData()) {
00711 $select->where("e.is_child=?", 0);
00712 }
00713 if (!is_null($productIds)) {
00714 $select->where('main_table.entity_id IN(?)', $productIds);
00715 }
00716 $sql = $select->crossUpdateFromSelect(array('e' => $this->getFlatTableName($store)));
00717 $this->_getWriteAdapter()->query($sql);
00718 }
00719 else {
00720 $select = $attribute->getFlatUpdateSelect($store);
00721 if ($select instanceof Varien_Db_Select) {
00722 if (!is_null($productIds)) {
00723 $select->where('e.entity_id IN(?)', $productIds);
00724 }
00725 $sql = $select->crossUpdateFromSelect(array('e' => $this->getFlatTableName($store)));
00726 $this->_getWriteAdapter()->query($sql);
00727 }
00728 }
00729 return $this;
00730 }
00731
00732
00733
00734
00735
00736
00737
00738
00739 public function updateEavAttributes($store, $productIds = null)
00740 {
00741 foreach ($this->getAttributes() as $attribute) {
00742
00743 if ($attribute->getBackend()->getType() != 'static') {
00744 $this->updateAttribute($attribute, $store, $productIds);
00745 }
00746 }
00747 return $this;
00748 }
00749
00750
00751
00752
00753
00754
00755
00756 public function updateEventAttributes($store = null)
00757 {
00758 Mage::dispatchEvent('catalog_product_flat_rebuild', array(
00759 'store_id' => $store,
00760 'table' => $this->getFlatTableName($store)
00761 ));
00762 }
00763
00764
00765
00766
00767
00768
00769
00770 public function getProductTypeInstances()
00771 {
00772 if (is_null($this->_productTypes)) {
00773 $this->_productTypes = array();
00774 $productEmulator = new Varien_Object();
00775
00776 foreach (array_keys(Mage_Catalog_Model_Product_Type::getTypes()) as $typeId) {
00777 $productEmulator->setTypeId($typeId);
00778 $this->_productTypes[$typeId] = Mage::getSingleton('catalog/product_type')
00779 ->factory($productEmulator);
00780 }
00781 }
00782 return $this->_productTypes;
00783 }
00784
00785
00786
00787
00788
00789
00790
00791
00792 public function updateRelationProducts($store, $productIds = null)
00793 {
00794 if (!$this->getFlatHelper()->isAddChildData()) {
00795 return $this;
00796 }
00797
00798 foreach ($this->getProductTypeInstances() as $typeInstance) {
00799 if (!$typeInstance->isComposite()) {
00800 continue;
00801 }
00802 $relation = $typeInstance->getRelationInfo();
00803 if ($relation
00804 and $relation->getTable()
00805 and $relation->getParentFieldName()
00806 and $relation->getChildFieldName()
00807 ) {
00808 $columns = $this->getFlatColumns();
00809 $fieldList = array_keys($columns);
00810 unset($columns['entity_id']);
00811 unset($columns['child_id']);
00812 unset($columns['is_child']);
00813
00814 $select = $this->_getWriteAdapter()->select()
00815 ->from(
00816 array('t' => $this->getTable($relation->getTable())),
00817 array($relation->getParentFieldName(), $relation->getChildFieldName(), new Zend_Db_Expr('1')))
00818 ->join(
00819 array('e' => $this->getFlatTableName($store)),
00820 "`e`.`entity_id`=`t`.`{$relation->getChildFieldName()}`",
00821 array_keys($columns)
00822 );
00823 if (!is_null($relation->getWhere())) {
00824 $select->where($relation->getWhere());
00825 }
00826 if (!is_null($productIds)) {
00827 $cond = array(
00828 $this->_getWriteAdapter()->quoteInto("{$relation->getChildFieldName()} IN(?)", $productIds),
00829 $this->_getWriteAdapter()->quoteInto("{$relation->getParentFieldName()} IN(?)", $productIds)
00830 );
00831
00832 $select->where(join(' OR ', $cond));
00833 }
00834 $sql = $select->insertFromSelect($this->getFlatTableName($store), $fieldList);
00835 $this->_getWriteAdapter()->query($sql);
00836 }
00837 }
00838
00839 return $this;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849 public function updateChildrenDataFromParent($store, $productIds = null)
00850 {
00851 if (!$this->getFlatHelper()->isAddChildData()) {
00852 return $this;
00853 }
00854
00855 $select = $this->_getWriteAdapter()->select();
00856 foreach (array_keys($this->getFlatColumns()) as $columnName) {
00857 if ($columnName == 'entity_id' || $columnName == 'child_id' || $columnName == 'is_child') {
00858 continue;
00859 }
00860 $select->from(null, array($columnName => new Zend_Db_Expr('`t1`.`'. $columnName.'`')));
00861 }
00862 $select
00863 ->joinLeft(
00864 array('t1' => $this->getFlatTableName($store)),
00865 "`t2`.`child_id`=`t1`.`entity_id` AND `t1`.`is_child`=0",
00866 array())
00867 ->where('t2.is_child=1');
00868
00869 if (!is_null($productIds)) {
00870 $select->where('t2.child_id IN(?)', $productIds);
00871 }
00872
00873 $sql = $select->crossUpdateFromSelect(array('t2' => $this->getFlatTableName($store)));
00874 $this->_getWriteAdapter()->query($sql);
00875
00876 return $this;
00877 }
00878
00879
00880
00881
00882
00883
00884
00885 public function cleanRelationProducts($store)
00886 {
00887 if (!$this->getFlatHelper()->isAddChildData()) {
00888 return $this;
00889 }
00890
00891 foreach ($this->getProductTypeInstances() as $typeInstance) {
00892 if (!$typeInstance->isComposite()) {
00893 continue;
00894 }
00895 $relation = $typeInstance->getRelationInfo();
00896 if ($relation
00897 and $relation->getTable()
00898 and $relation->getParentFieldName()
00899 and $relation->getChildFieldName()
00900 ) {
00901 $select = $this->_getWriteAdapter()->select()
00902 ->distinct(true)
00903 ->from(
00904 $this->getTable($relation->getTable()),
00905 "{$relation->getParentFieldName()}"
00906 )
00907 ;
00908 $joinLeftCond = null;
00909 if (!is_null($relation->getWhere())) {
00910 $select->where($relation->getWhere());
00911 $joinLeftCond = ' AND ' . $relation->getWhere();
00912 }
00913
00914 $entitySelect = new Zend_Db_Expr($select->__toString());
00915
00916 $select = $this->_getWriteAdapter()->select()
00917 ->from(
00918 array('e' => $this->getFlatTableName($store)),
00919 null
00920 )
00921 ->joinLeft(
00922 array('t' => $this->getTable($relation->getTable())),
00923 "e.entity_id=t.{$relation->getParentFieldName()} AND e.child_id=t.{$relation->getChildFieldName()}"
00924 . $joinLeftCond,
00925 array())
00926 ->where("e.is_child=?", 1)
00927 ->where("e.entity_id IN(?)", $entitySelect)
00928 ->where("t.{$relation->getChildFieldName()} IS NULL");
00929
00930 $sql = $select->deleteFromSelect('e');
00931 $this->_getWriteAdapter()->query($sql);
00932 }
00933 }
00934
00935 return $this;
00936 }
00937
00938
00939
00940
00941
00942
00943
00944
00945 public function removeProduct($productIds, $store)
00946 {
00947 $cond = array(
00948 $this->_getWriteAdapter()->quoteInto('entity_id IN(?)', $productIds)
00949 );
00950 if ($this->getFlatHelper()->isAddChildData()) {
00951 $cond[] = $this->_getWriteAdapter()->quoteInto('child_id IN(?)', $productIds);
00952 }
00953 $cond = join(' OR ', $cond);
00954 $this->_getWriteAdapter()->delete($this->getFlatTableName($store), $cond);
00955
00956 return $this;
00957 }
00958
00959
00960
00961
00962
00963
00964
00965
00966 public function removeProductChildren($productIds, $store)
00967 {
00968 if (!$this->getFlatHelper()->isAddChildData()) {
00969 return $this;
00970 }
00971 $cond = array(
00972 $this->_getWriteAdapter()->quoteInto('entity_id IN(?)', $productIds),
00973 $this->_getWriteAdapter()->quoteInto('is_child=?', 1),
00974 );
00975 $this->_getWriteAdapter()->delete($this->getFlatTableName($store), $cond);
00976
00977 return $this;
00978 }
00979
00980
00981
00982
00983
00984
00985
00986
00987 public function updateProduct($productIds, $store)
00988 {
00989 $this->saveProduct($productIds, $store);
00990
00991 Mage::dispatchEvent('catalog_product_flat_update_product', array(
00992 'store_id' => $store,
00993 'table' => $this->getFlatTableName($store),
00994 'product_ids' => $productIds
00995 ));
00996
00997 return $this;
00998 }
00999
01000
01001
01002
01003
01004
01005
01006
01007 public function saveProduct($productIds, $store)
01008 {
01009 $this->updateStaticAttributes($store, $productIds);
01010 $this->updateEavAttributes($store, $productIds);
01011
01012 return $this;
01013 }
01014
01015
01016
01017
01018
01019
01020
01021 public function deleteFlatTable($store)
01022 {
01023 $tableName = $this->getFlatTableName($store);
01024 $tableNameQuote = $this->_getWriteAdapter()->quoteIdentifier($tableName);
01025 $tableExistsSql = $this->_getWriteAdapter()
01026 ->quoteInto("SHOW TABLE STATUS LIKE ?", $tableName);
01027 if ($this->_getWriteAdapter()->query($tableExistsSql)) {
01028 $sql = sprintf('DROP TABLE IF EXISTS %s', $tableNameQuote);
01029 $this->_getWriteAdapter()->query($sql);
01030 }
01031
01032 return $this;
01033 }
01034
01035
01036
01037
01038
01039
01040
01041
01042 protected function _arrayPrevKey(array $array, $key)
01043 {
01044 $prev = false;
01045 foreach (array_keys($array) as $k) {
01046 if ($k == $key) {
01047 return $prev;
01048 }
01049 $prev = $k;
01050 }
01051 return false;
01052 }
01053
01054
01055
01056
01057
01058
01059
01060
01061 protected function _arrayNextKey(array $array, $key)
01062 {
01063 $next = false;
01064 foreach (array_keys($array) as $k) {
01065 if ($next === true) {
01066 return $k;
01067 }
01068 if ($k == $key) {
01069 $next = true;
01070 }
01071 }
01072 return false;
01073 }
01074 }