创建可配置的产品Configurable Product

接着上篇文章写点技术性文章,再次充实下Magento让人汗颜的开发文档。这次我要创建的是Configurable Product。创建该类型的产品是相当的复杂。首先必须创建一个全局Global的属性,类型为Drodown,设置Ues To Create Configurable这Product 为 Yes。这样新建一个Configurable Product 的时候选择这个属性就可以了。建议新建一个单独的Attribute Set,例如Configurable,把需要配置的属性,例如size加入到这个Configurable的属性组。 然后创建独立的simple类型的产品,设置size这个属性值,即可与Configurable Product 建立关联。下面这段代码就是建立产品之间的联系。

前期准备

创建一个全局Global的size属性,设置类型为Dropdown,设置Use to设置为Yes。设置size的值为S、M、L。创建一个属性集Attribute Set为Configurable,添加size属性到该属性集。

$attribute = array(
	// 定义Size基本属性
	'value' => array(
		'label' 	 => 'Size',
		'attribute_code' => 'size',
		'frontend_label' => 'Size',
		'store_label'	 => 'Size',
	),
	//定义size的3种大小
	'size' => array(
		'0' => 'S',
		'1' => 'M',
		'2' => 'L',	
	),
	//定义size属性的attribute id
	'id' => array(
		'size' => '128'
	),
	//定义size的3个option的index value
	'options' => array(
		'size' => array(
			'S' => '3',
			'M' => '4',
			'L' => '5',
		),
	),
	//定义size属性的3种价钱
	'price' => array(
		'size' => array(
			'S' => '10',
			'M' => '20',
			'L' => '30',
		)
	)
);

属性与产品进行关联

创建Configurable Product

$data = array(
	'qty' => '999',
	'sku' => 'configurable',
	'price' => '0',
	'weight' => '100',
	'status' => 'Enabled',
	'is_in_sock' => '1',
	'name' => 'Configurable Product',
	'description' => 'Configurable Product',
	'visibility' => 'Catalog, Search',
	'attribute_set' => 'Default',
	'type' => 'configurable',
	'website' => 'base',
);
$model = Mage::getModel('catalog/convert_adapter_product');
$model->saveRow($data);
$configProductId = $model->getProductModel->getId();
$sku = $data['sku'];
$name = $data['name'];

创建3个simple Product,因为size的值有3个。并创建与Configruable Product 属性关联的数组$configurable_products_data

$attributeData = array();
$configAttributeData = array();
$configurable_products_data = array();
//default stre id is 1
$storeId = 1;
for($i = 0;$i < 3;$i++){
	$data['type'] = 'simple';
	$data['name'] = $name.'-'.$i;
	$data['sku']  = $sku.'-'.$i;
	$data['visibility']= 'Not Visible Individually';
	$data['price'] = '100';//price = configproduct price +simple product price
	$model->saveRow($data);
	//get simple product id 
	$productId = $model->getProductModel()->getId();
	// THE POINT: update the super attribute ,Magento call it super attribute
	//注意这里关联Configurable的绝招:设置产品的Size属性
	$attributeData['size'] = $attribute['size'][$i];
	Mage::getSingleton('catalog/product_action')->updateAttributes(array($productId), $attributeData, $storeId);
	//构造产品关联数组
	$configAttributeData = array(
    				'label' 	=> $attributeData['size'],
    				'attribute_id'	=> $attribute['id']['size'],
    				'value_index'	=> $attribute['options']['size'][$attributeData['size']],
    				'is_percent'	=> '0',
    				'pricing_value' => $attribute['price']['size'][$attributeData['size']],
    			);
	$configurable_products_data[$productId][] = $configAttributeData;
}

Configurable Product关联Size属性

$configurable_attributes_data = array();
$configurable_attributes_data[] = array(
	'id' 		=>	null,
    	'label'		=>	$attribute['value']['label'],
    	'use_default'	=>	null,
    	'position'	=>	null,
    	'values'	=>	array(),
    	'attribute_id'	=>	$this->_importAttribute['value'][$key],
    	'attribute_code'=>	$attribute['value']['attrinbute_code'],
    	'frontend_label'=>	$attribute['value']['frontend_label'],
    	'store_label'	=>	$attribute['value']['store_label'],
    	'html_id'	=>	'configurable__attribute_0',
);
$product = Mage::getModel('catalog/product');
$product = $product->load($configProductId);
$superAttribteIds = array();
// set product super attribute
//再次发个大招:Configurable Product 关联Size属性
foreach ($configurable_attributes_data as $attributeData) {
                $id = isset($attributeData['id']) ? $attributeData['id'] : null;
                $model = Mage::getModel('catalog/product_type_configurable_attribute')
                   ->setData($attributeData)
                   ->setId($id)
                   ->setStoreId($product->getStoreId())
                   ->setProductId($product->getId())
                   ->save();
                $superAttribteIds[$attributeData['label']] = $model->getId();
        }
//设置关联属性的id
//set super attribute id of config attribute data
foreach ($configurable_attributes_data as $k => $v){
        if($value = $superAttribteIds[$v['label']]){
        	$configurable_attributes_data[$k]['id'] = $value;
        }
}

构造simple 和Confinurable Product的关联数组

//构造出来的数组大致是这个样子的
//$configurable_products_data
array(
	'2' => array(
		array(
			'label' => 'Size',
      			'attribute_id' => '128',
      			'value_index' => '3',
      			'is_percent' => '0',
      			'pricing_value' => '10',
		)
	),
	'3' => array(
		array(
			'label' => 'Size',
      			'attribute_id' => '128',
      			'value_index' => '4',
      			'is_percent' => '0',
      			'pricing_value' => '20',
		)
	),
	'4' => array(
		array(
			'label' => 'Size',
      			'attribute_id' => '128',
      			'value_index' => '5',
      			'is_percent' => '0',
      			'pricing_value' => '30',
		)
	)
)
 
//$configurable_attributes_data
array (
	array (
    		'id' => '1',
    		'label' => 'Size',
    		'use_default' => NULL,
    		'position' => NULL,
    		'values' =>
			array (
      				array (
        				'label' => 'Size',
        				'attribute_id' => '128',
        				'value_index' => '3',
        				'is_percent' => '0',
        				'pricing_value' => '10.0000',
      				), 
      				array (
        				'label' => 'Size',
        				'attribute_id' => '128',
        				'value_index' => '4',
        				'is_percent' => '0',
        				'pricing_value' => '20.0000',
      				), 
      				array (
        				'label' => 'Size',
        				'attribute_id' => '128',
        				'value_index' => '5',
        				'is_percent' => '0',
        				'pricing_value' => '30.0000',
      				),
    			),
    		'attribute_id' => '128',
    		'attribute_code' => 'size',
    		'frontend_label' => 'Size',
    		'store_label' => 'Size',
    		'html_id' => 'configurable__attribute_0',
  	),
)
 
//refer app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
//line 91
$product->setConfigurableProductsData($configurable_products_data);
$product->setConfigurableAttributesData($configurable_attributes_data);
$product->setCanSaveConfigurableAttributes(1);
try{
    $product->save();
    //return $product->getId();
}
catch (Exception $e){
    echo Mage::helper('core')->__('Configurable Product ID %s CAN NOT  be saved because of %s', $configProductId , $e->getMessage()));
}

参考资料

Bulk Update Product Attribute

Configurable Products in Magento

使用Magento Api创建configurable product

创建Attribute 和 Attribute Set

自从上次总结后,俺是忙得团团转,忙着找工作,忙着打代码,忙着忙着,一晃一个月就过去了。清明放假除了祭奠亲人外,顺便总结下最近的成果。最近一直在忙的项目是数据导入。从在我看来后台"很原始"的Zencart 平台迁移到扩展性强,性能很弱的Magentlo上。在迁移数据的过程中,遇到了需要创建Attibute Set的问题,在这里记录下我的解决方案。btw,在我看来,Mqgento的开发文挡匮乏得令人发指的程度,还有这么多优秀插件出现,这不得不得让人相信这是个奇迹!好了,废话不多说,上代码儿。

获取默认的Attribute Set 和Gourp Id

<?php 
//get default type id 
$entityTypeId = Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId();
//get default type id
//$entityTypeId = Mage::getModel('catalog/product')->getResource()->getTypeId();
 
//get Default Attribute Set id
$defaultAttributeSetID = Mage::getModel('eav/entity_attribute_set')->getCollection()
->setEntityTypeFilter($entityTypeId)
->addFiledToFilter('attribute_set_name','Default')
->getFirstItem()
->getAttributeSetId();
?>

创建自定义的Attribute Set

//create Attribute Set Name: Configurable;
//refer app/code/core/Mage/Adminhtml/controllers/Catalog/Product/SetController.php 
// line 142
$model = Mage::getModel('eav/entity_attribute_set');
$entityTypeID = Mage::getModel('catalog/product')->getResource()->getTypeId();
$model->setEntityTypeId($entityTypeID);
$model->setAttributeSetName('Configurable');
$model->validate();
$model->save();
$model->initFromSkeleton($defaultAttributeSetID);
$model->save();
 
//get the Create Attribute Set ID and Group ID
$attributeSet = array();
$attributeSet['id'] = $model->getId();
$attributeSet['group_id'] = $model->load($attributeSet['id'])->getDeafultGroupId();

创建自定义属性

//create attribute function
// refer app/code/core/Mage/Adminhtml/controllers/Ctalog/Product/AttribteController.php
// line 186
function createAttribute($code, $label, $attribute_type, $product_type , 
$deafultValue = array() , $attributeSet , $isRequired = '0' , $isConfigurable = 1){
    	$data = array(
        	'attribute_code' => $code,
        	'is_global' => '1',
        	'frontend_input' => $attribute_type,
        	'default_value_text' => '',
        	'default_value_yesno' => '0',
        	'default_value_date' => '',
        	'default_value_textarea' => '',
        	'is_unique' => '0',
        	'is_required' => $isRequired,
        	'apply_to' => array($product_type),
        	'is_configurable' => $isConfigurable,
        	'is_searchable' => '0',
        	'is_visible_in_advanced_search' => '0',
        	'is_comparable' => '0',
        	'is_used_for_price_rules' => '0',
        	'is_wysiwyg_enabled' => '0',
        	'is_html_allowed_on_front' => '1',
        	'is_visible_on_front' => '0',
        	'used_in_product_listing' => '0',
        	'used_for_sort_by' => '0',
        	'frontend_label' => array($label)
    	);
 
    	$model = Mage::getModel('catalog/resource_eav_attribute');
 
    	if (!isset($data['is_configurable'])) {
        	$data['is_configurable'] = 0;
    	}
    	if (!isset($data['is_filterable'])) {
        	$data['is_filterable'] = 0;
    	}
    	if (!isset($data['is_filterable_in_search'])) {
        	$data['is_filterable_in_search'] = 0;
    	}
 
    	if (is_null($model->getIsUserDefined()) || $model->getIsUserDefined() != 0) {
        	$data['backend_type'] = 
			$model->getBackendTypeByInput($data['frontend_input']);
    	}
 
    	$data['option']['value'] = $deafultValue;
 
    	$model->addData($data);
 	$typeId = Mage::getModel('eav/entity')->setType('catalog_product')->getTypeId();
    	$model->setEntityTypeId($typeId);
    	$model->setIsUserDefined(1);
	if($attributeSet && isset($attributeSet['id']) && isset($attributeSet['group_id'])){
    		//set attibute to the Attribute Set
 		$model->setAttributeSetId($attributeSet['id']);
        	$model->setAttributeGroupId($attributeSet['group_id']);
	}
 
    	try {
        	$model->save();
        	return $model->getId();
    	}
    	catch (Exception $e) { 
    		echo '<p>Sorry, error occured while trying to save the attribute. Error: '.$e->getMessage().'</p>';
    	}
    }
// create select attribute
createAttribute('xbc_select','Xbc Select','select','simple');
//create text attribute
createAttribute('xbc_text','Xbc Text','text','grouped');
//create boolean attribute
createAttribute('xbc_bool','Xbc Bool','bollean','');
?>

以上代码在Magento Community 1.6.2测试通过

参考资料

Programatically create attribute in Magento, useful for the “on the fly” import system

Programmatically Adding Attributes and Attribute Sets

Playing with Attribute Set in Magento