Magento - How to assign simple products to configurable programmatically?

Posted by Damodar Bashyal on July 10, 2012

 

Some of our simple products were not correctly assigned to a configurable product. And, some of them were visible independently in the front end. My task was to assign simple products to correct configurable product and make associated products to not visible individually. It was easy to find configurable product and associated simple products because of the SKU they had. All simple products had sku configurableSKU__*.

So after some trials this code worked for me.

<?php
/**
 * Associate simple products to configurable products
 * Re-written By Damodar because of memory issue with previous code.
 *
 * @category   	Technooze
 * @package     Add simple products to configurable products
 * @copyright  	Copyright (c) 2012 Technooze.com
 * @author		Damodar Bashyal
 * @license    	http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 *
 */
require_once dirname(__FILE__) . '/../app/Mage.php';
class Mage_Shell_setChildren {
    public function run() {
		// because of the memory issue, i need to use cache file
        $cacheFile = 'configurable.txt';
        // display a startup message
        echo "\n\rOpening file...";
        // check to see if file exists, if not attempt to create it
        if(!file_exists($cacheFile)){
            $fh = fopen($cacheFile, 'w+') or die("can't open file - {$cacheFile}");
            fclose($fh);
        }
        // read file into array
        $file_contents = file($cacheFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        // if the file content is empty, then look into database and write into file
        if(empty($file_contents)){
            echo "\n\rNo Ids found in file, so looking into database";
            $collectionConfigurable = Mage::getResourceModel('catalog/product_collection')
                ->addAttributeToFilter('type_id', array('eq' => 'configurable'))
                //->addAttributeToFilter('has_been_fixed', array('eq' => '0'))
                //->addAttributeToFilter('sku', array('eq' => '10SOC04RD'))
            ;
            $configurableIds = array();
            if($total = count($collectionConfigurable)){
                foreach ($collectionConfigurable as $parent) {
                    $configurableIds[] = $parent->getId();
                }
            }
            // write in a file, so we can read file instead of quering database later
            file_put_contents($cacheFile, implode("\n",$configurableIds));
        } else {
            $total = count($file_contents);
            $configurableIds = $file_contents;
            echo "\n\rIds found in cache file, so using those Ids";
        }
        // free some memory
        unset($file_contents);
        $loop = 1;
        echo "\n\rFound total: {$total} configurable product IDs";
        // now iterate through the ids and update products.
        foreach ($configurableIds as $k => $id) {
            $parent = Mage::getModel('catalog/product')->load($id);
            echo "\n\r" . $loop++ . '. Processing SKU - ' . $parent->getSku() . ' - ' . $parent->getId() . "\n\r";
            // get existing associated product ids
            $childIds = $parent->getTypeInstance()->getUsedProductIds();
            // look for simple products that could be associated products of this configurable product
            $collectionPosChildren = Mage::getResourceModel('catalog/product_collection')
                ->addAttributeToFilter('type_id', array('eq' => 'simple'))
                ->addAttributeToFilter('sku', array('like' => $parent->getSku() . "__%"));
				// get ids of associated products and set the as not visible individually
            foreach ($collectionPosChildren as $product) {
                $childIds[] = $product->getId();
                $product = $product->load($product->getId());
                echo "\n\rsetting simple product ({$product->getSku()}) as not visible individually!";
                $product->setVisibility(Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE);
                $product->save();
            }
            // we don't need this $product variable, so unset it to free memory
            unset($product);
            // make the array of associated products ids unique
            $childIds = array_unique($childIds);
            // save parent id on variable as it's lost after next step, not sure why
            $parentId = $parent->getId();
            // now load the resource model for this configurable product and save it with associated product ids
            $product = Mage::getResourceModel( 'catalog/product_type_configurable' )->load( $parent, $parent->getId() );
            echo "\n\rSaving configurable product...\n\r";
            $product->saveProducts( $parentId, $childIds );
            // now lets remove this id from our cache file and overwrite with remaining ids
            unset($configurableIds[$k]);
            echo "\n\rUpdating cache file...\n\r";
            file_put_contents($cacheFile, implode("\n",$configurableIds));
            $k++;
            echo "\n\r{$k} of {$total} completed!!!\n\r\n\r\n\r";
        }
        echo "\n\r\n\rDone!!!\n\r\n\r";
    }
}
umask(0);
/* not Mage::run(); */
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);
error_reporting(E_ALL ^ E_NOTICE);
$shell = new Mage_Shell_setChildren();
$shell->run();
//end of file: shell/associateSimples.php

This is how i run in the php command line:

shell > php associateSimples.php

Sample output:

1. Processing SKU - SOC22WH - 420
	ID - 420
2. Processing SKU - FOK22WH - 469
	ID - 469

WP posted on - Monday 26th of November 2012 09:24:35 PM

I'm having the same problem. I thought it might have something to do with load the product as a resource model as opposed to a model, but that didn't work either.

Ovidiu U posted on - Monday 29th of October 2012 08:01:28 PM

Hi,
I'm getting this error on your script:
Saving configurable product...
PHP Fatal error: Call to a member function getTypeInstance() on a non-object in /var/www/html/www.lenjerii1701.com/app/code/core/Mage/Catalog/Model/Resource/Product/Type/Configurable.php on line 62

This is called by $product->saveProducts( $parentId, $childIds );

Any Ideea why is this happening?

Andrew posted on - Tuesday 4th of December 2012 11:09:59 AM

Hi,

the issue is something has changed in Magento, you need to pass the parent product model, not just the ID.

like this:

$product->saveProducts( $parentProduct, $childIds );

Julian posted on - Thursday 24th of January 2013 10:19:28 AM

Hi,

I have some regarding problem, I need to add one certain simple to all existing configs. I tried several options on API or Magmi but nothing worked out so far. The task is to add that certain simple to all configs wihtout deleting existing associated simples, or doing a complete new import. Maybe one of you have an idea how to solve that issue.

Best

Hamid posted on - Friday 25th of January 2013 07:38:40 PM

to fix the error replace it with: $product->saveProducts( $parent, $childIds );

The simple products are then nicely associated to the configurable product.

Keep in mind the logic of the names is as following:
configurable: mainconfig
simple product1: mainconfig1
simple product2: mainconfig2

Or you can change it ofcourse by changing:
addAttributeToFilter('sku', array('like' => $parent->getSku() . "%"));

Good luck.

Nicholas posted on - Thursday 11th of April 2013 11:12:44 PM

I am getting this error please help

Saving configurable product...

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`hyperion_hyperionsupps`.`catalog_product_super_link`, CONSTRAINT `FK_CAT_PRD_SPR_LNK_PARENT_ID_CAT_PRD_ENTT_ENTT_ID` FOREIGN KEY (`parent_id`) REFERENCES `catalog_product_entity` (`entity_id`)' in /home/hyperion/public_html/test/lib/Zend/Db/Statement/Pdo.php:228
Stack trace:
#0 /home/hyperion/public_html/test/lib/Zend/Db/Statement/Pdo.php(228): PDOStatement->execute(Array)
#1 /home/hyperion/public_html/test/lib/Varien/Db/Statement/Pdo/Mysql.php(110): Zend_Db_Statement_Pdo->_execute(Array)
#2 /home/hyperion/public_html/test/lib/Zend/Db/Statement.php(300): Varien_Db_Statement_Pdo_Mysql->_execute(Array)
#3 /home/hyperion/public_html/test/lib/Zend/Db/Adapter/Abstract.php(479): Zend_Db_Statement->execute(Array)
#4 /home/hyperion/public_html/test/lib/Zend/Db/Adapter/Pdo/Abstract.php(238): Zend_Db_Adapter_Abstract->query('INSERT INTO `ca...', Array)
in /home/hyperion/public_html/test/lib/Zend/Db/Statement/Pdo.php on line 234

Naujasdizainas posted on - Monday 13th of May 2013 12:17:25 PM

I think can add
after
require_once dirname(__FILE__) . '/../app/Mage.php';
ADD
//Truncate catalog_product_super_link
$_db = Mage::getSingleton('core/resource')->getConnection('core_read');
$_db->query("TRUNCATE catalog_product_super_link");
 
not published on website


QR Code: Magento - How to assign simple products to configurable programmatically?