Last active
December 17, 2015 08:08
-
-
Save edannenberg/5577420 to your computer and use it in GitHub Desktop.
Fixes possible borked filtered navigation after upgrading older Magento versions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This will replicate attribute values of configurable products to all it's child products. | |
* | |
* Rationale: After upgrading Magento 1.4 to 1.7 we found that our filtered navigation was | |
* missing quite alot of products. Turns out somewhere after 1.4 Varien changed the filtered | |
* navigation to only use the attributes of child products, ignoring the attributes of | |
* their configurable products. | |
* | |
* Drop this into the shell directory of your Magento installation and run with -h to see all options. | |
* | |
*/ | |
require_once 'abstract.php'; | |
/** | |
* Replicates attribute values of configurable products to all it's childs. | |
* | |
* @author Erik Dannenberg <erik.dannenberg@bbe-consulting.de> | |
*/ | |
class BbeConsulting_Replicate_Attributes extends Mage_Shell_Abstract | |
{ | |
/** var string */ | |
protected $_defaultAttrCodes = 'color,gender,manufacturer'; | |
/** var bool */ | |
protected $_reindexAll = false; | |
/** var Varien_Db_Adapter_Interface */ | |
protected $_adapter; | |
/** var string */ | |
protected $_attributeCodes; | |
/** var string */ | |
protected $_dateLimit; | |
/** var bool */ | |
protected $_quietMode; | |
/** var int */ | |
protected $_maxCount; | |
/** var int */ | |
protected $_doneCount = 0; | |
/** var int */ | |
protected $_updatedChildCount = 0; | |
public function __construct() { | |
parent::__construct(); | |
register_shutdown_function(array($this, 'destruct')); | |
$this->_setMagentoIndexerMode(Mage_Index_Model_Process::MODE_MANUAL); | |
} | |
public function destruct() { | |
// rollback if script got aborted during a transaction | |
if ($this->_adapter->getTransactionLevel() === 1) { | |
$this->_adapter->rollback(); | |
} | |
if ($this->_reindexAll && !$this->_quietMode) { | |
echo 'Reindexing everything, this may take a while..' . "\n"; | |
} | |
$this->_setMagentoIndexerMode(Mage_Index_Model_Process::MODE_REAL_TIME, $this->_reindexAll); | |
} | |
public function run() { | |
$this->_showHelp(); | |
if ($this->getArg('cronMode')) { | |
$this->_dateLimit = date('Y-m-d', strtotime('-1 day')); | |
} | |
if ($this->getArg('quiet')) { | |
$this->_quietMode = true; | |
} | |
if ($this->getArg('reindexAll')) { | |
$this->_reindexAll = true; | |
} | |
if ($this->getArg('attrCodes')) { | |
$this->_attributeCodes = $this->getArg('attrCodes'); | |
} else { | |
$this->_attributeCodes = $this->_defaultAttrCodes; | |
} | |
$this->_replicateProductAttributes(); | |
} | |
protected function _replicateProductAttributes() { | |
$startTime = time(); | |
$sourceCol = Mage::getResourceModel('catalog/product_collection') | |
->addAttributeToFilter('type_id', array('eq' => 'configurable')); | |
if ($this->_dateLimit) { | |
$sourceCol->addAttributeToFilter('created_at', array('gteq' => $this->_dateLimit)); | |
} | |
$this->_adapter = $sourceCol->getConnection(); | |
$this->_maxCount = $sourceCol->count(); | |
$this->_attributeCodes = explode(',', $this->_attributeCodes); | |
Mage::getSingleton('core/resource_iterator')->walk( | |
$sourceCol->getSelect(), | |
array(array($this, 'collectionCallback')), | |
array(), | |
$this->_adapter); | |
if (!$this->_quietMode) { | |
$totalTime = number_format(time()-$startTime); | |
$rate = number_format($this->_updatedChildCount / $totalTime); | |
echo 'Updated ' . $this->_updatedChildCount . ' Products in ' . $totalTime . ' seconds. (' . $rate .'p/s)' ."\n"; | |
} | |
} | |
/** | |
* Callback for collection iterator | |
* | |
* @param array $args | |
*/ | |
public function collectionCallback($args) { | |
$product = Mage::getModel('catalog/product'); | |
$product->load($args['row']['entity_id']); | |
$productData = $product->getData(); | |
$attributeValues = array(); | |
foreach ($this->_attributeCodes as $attrCode) { | |
if (array_key_exists($attrCode, $productData)) { | |
$attributeValues[$attrCode] = $productData[$attrCode]; | |
} | |
} | |
$children = Mage::getModel('catalog/product_type_configurable')->getChildrenIds($product->getId()); | |
$storeId = 0; | |
if (!$this->_quietMode) { | |
++$this->_doneCount; | |
$percDone = (double)($this->_doneCount/$this->_maxCount); | |
$status = "\r " . number_format($percDone*100, 0) . "% $this->_doneCount/$this->_maxCount"; | |
$status .= " - Updating " . count($children[0]) . " childs for: " . $product->getName() . " (ID: ". $product->getId() . ")"; | |
$status .= "\033[K"; // clear end of line | |
if ($this->_doneCount == $this->_maxCount) { | |
$status .= "\n"; | |
} | |
echo $status; | |
} | |
if (count($children[0]) > 0) { | |
Mage::dispatchEvent('catalog_product_attribute_update_before', array( | |
'attributes_data' => &$attributeValues, | |
'product_ids' => &$children[0], | |
'store_id' => &$storeId | |
)); | |
Mage::getResourceSingleton('catalog/product_action')->updateAttributes($children[0], $attributeValues , $storeId); | |
$this->_updatedChildCount += count($children[0]); | |
} | |
$product->clearInstance(); // prevent memleaks | |
//Mage::log(memory_get_usage(true)); | |
} | |
/** | |
* @param var Mage_Index_Model_Process::MODE_* $mode | |
*/ | |
protected function _setMagentoIndexerMode($mode, $reindexAll=false) { | |
$processes = Mage::getSingleton('index/indexer')->getProcessesCollection(); | |
if ($reindexAll) { | |
$processes->walk('reindexAll'); | |
} | |
$processes->walk('setMode', array($mode)); | |
$processes->walk('save'); | |
} | |
/** | |
* Retrieve Usage Help Message | |
*/ | |
public function usageHelp() | |
{ | |
return <<<USAGE | |
Usage: php -f replicate-attribute-values.php | |
--attrCodes Comma separated list of attribute codes to replicate. default: color,gender,manufacturer | |
--reindexAll Reindex everything after script finished. true|false default: false | |
--cronMode Only replicate attributes of products that were created in the last 24 hours. true|false default: false | |
--quiet No shell output generated. true|false default: false | |
help This help | |
USAGE; | |
} | |
} | |
// signal handling, requires PCNTL feature in PHP, php -m | grep pcntl | |
// remove this block if you are on windows, it is not supported | |
// just be aware that the indexer state will be left on manual on script abortion/error | |
declare(ticks = 1000); | |
function sig_handler($signal) { | |
switch($signal) { | |
case SIGTERM: | |
case SIGKILL: | |
case SIGINT: | |
die("Aborting... \n"); | |
} | |
} | |
pcntl_signal(SIGTERM, "sig_handler"); | |
pcntl_signal(SIGINT, "sig_handler"); | |
// end of signal handling | |
$shell = new BbeConsulting_Replicate_Attributes(); | |
$shell->run(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment