Archive for the ‘ Magento ’ Category

分享一段Magento关于刷新索引的代码

在调整Magento的Index,偶然间看到这样一段代码,写得很好,摘录出来分享下。

/**
* Reindex all data what this process responsible is
*
* @return unknown_type
*/
public function reindexAll()
{
if ($this->isLocked()) {
Mage::throwException(Mage::helper('index')->__('%s Index process is working now. Please try run this process later.', $this->getIndexer()->getName()));
}
$this->_getResource()->startProcess($this);
$this->lock();
$this->getIndexer()->reindexAll();
$this->unlock();
$this->_getResource()->endProcess($this);
}

/**
* Lock process without blocking.
* This method allow protect multiple process runing and fast lock validation.
*
* @return Mage_Index_Model_Process
*/
public function lock()
{
$this->_isLocked = true;
flock($this->_getLockFile(), LOCK_EX | LOCK_NB);
return $this;
}

/**
* Lock and block process.
* If new instance of the process will try validate locking state
* script will wait until process will be unlocked
*
* @return Mage_Index_Model_Process
*/
public function lockAndBlock()
{
$this->_isLocked = true;
flock($this->_getLockFile(), LOCK_EX);
return $this;
}

/**
* Unlock process
*
* @return Mage_Index_Model_Process
*/
public function unlock()
{
$this->_isLocked = false;
flock($this->_getLockFile(), LOCK_UN);
return $this;
}

/**
* Get lock file resource
*
* @return resource
*/
protected function _getLockFile()
{
if ($this->_lockFile === null) {
$varDir = Mage::getConfig()->getVarDir('locks');
$file = $varDir . DS . 'index_process_'.$this->getId().'.lock';
if (is_file($file)) {
$this->_lockFile = fopen($file, 'w');
} else {
$this->_lockFile = fopen($file, 'x');
}
fwrite($this->_lockFile, date('r'));
}
return $this->_lockFile;
}

关于flock函数的用法。
/**
* Portable advisory file locking
* @link http://www.php.net/manual/en/function.flock.php
* @param handle resource <p>
* An open file pointer.
* </p>
* @param operation int <p>
* operation is one of the following:
* LOCK_SH to acquire a shared lock (reader).
* @param wouldblock int[optional] <p>
* The optional third argument is set to true if the lock would block
* (EWOULDBLOCK errno condition). (not supported on Windows)
* </p>
* @return bool Returns true on success or false on failure.
*/
function flock ($handle, $operation, &$wouldblock = null) {}

高级应用Magento-订单创建流程及程序代码

老规矩,直接看代码吧。下面的代码是如何通过程序创建一个完美订单。

<?php
require_once 'app/Mage.php';
 
Mage::app('default');//初始化程序,设置当前店铺
 
$store = Mage::app()->getStore('default');
//通过电子邮件获取用户,当然也可以不获取,创建guest订单
$customer = Mage::getModel('customer/customer');
$customer->setStore($store);
$customer->loadByEmail('email_address@gmail.com');
 
//初始化Quote,Magento的订单是通过Quote来转化过去的
$quote = Mage::getModel('sales/quote');
$quote->setStore($store);
$quote->assignCustomer($customer);//如果有用户则执行这个
 
$product1 = Mage::getModel('catalog/product')->load(166); /* HTC Touch Diamond */
$buyInfo1 = array('qty' => 1);
 
$product2 = Mage::getModel('catalog/product')->load(18); /* Sony Ericsson W810i */
$buyInfo2 = array('qty' => 3);
//添加商品到Quote
$quote->addProduct($product1, new Varien_Object($buyInfo1));
$quote->addProduct($product2, new Varien_Object($buyInfo2));
//设置账单和收货品地址
$billingAddress = $quote->getBillingAddress()->addData($customer->getPrimaryBillingAddress());
$shippingAddress = $quote->getShippingAddress()->addData($customer->getPrimaryShippingAddress());
//设置配送和支付方式
$shippingAddress->setCollectShippingRates(true)->collectShippingRates()
                ->setShippingMethod('flatrate_flatrate')
                ->setPaymentMethod('checkmo');
 
$quote->getPayment()->importData(array('method' => 'checkmo'));
//Quote计算运费
$quote->collectTotals()->save();
//将Quote转化为订单
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$order = $service->getOrder();
/***至此订单已经成功生成,下面是注册付款信息***/
 
$invoice = Mage::getModel('sales/service_order', $order)->prepareInvoice();
$invoice->setRequestedCaptureCase(Mage_Sales_Model_Order_Invoice::CAPTURE_ONLINE);
$invoice->register();
 
$transaction = Mage::getModel('core/resource_transaction')
                    ->addObject($invoice)
                    ->addObject($invoice->getOrder());
 
$transaction->save();

Nginx 配置 for Magento

应群众要求,把nginx配置晒出来了,适用于magento程序。主要请看server这段,其他的要针对自己服务器和用途配置。

user  nobody;
worker_processes  1;
 
#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;
 
#pid        logs/nginx.pid;
 
 
events {
    worker_connections  1024;
}
 
 
http {
        include       mime.types;
        default_type  application/octet-stream;
 
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
 
        #access_log off;
        server_names_hash_bucket_size 128;
        client_header_buffer_size 32k;
        large_client_header_buffers 4 32k;
        client_max_body_size 300m;
 
        sendfile on;
        tcp_nopush     on;
 
        keepalive_timeout 360000;
 
        tcp_nodelay on;
 
        client_body_buffer_size  512k;
        proxy_connect_timeout    5;
        proxy_read_timeout       60;
        proxy_send_timeout       5;
        proxy_buffer_size        16k;
        proxy_buffers            4 64k;
        proxy_busy_buffers_size 128k;
        proxy_temp_file_write_size 128k;
 
        fastcgi_connect_timeout 3600;
        fastcgi_send_timeout 3600;
        fastcgi_read_timeout 3600;
        fastcgi_buffer_size 64k;
        fastcgi_buffers 4 64k;
        fastcgi_busy_buffers_size 128k;
        fastcgi_temp_file_write_size 128k;
 
        gzip on;
        gzip_min_length  1k;
        gzip_buffers     4 16k;
        gzip_http_version 1.0;
        gzip_comp_level 2;
        gzip_types       text/plain application/x-javascript text/css application/xml;
        gzip_vary on;
 
        proxy_cache_path  /app/nginx/proxy_cache levels=2:2 keys_zone=one:200m inactive=1d max_size=30g;
        proxy_temp_path /app/nginx/proxy_temp;
 
        fastcgi_cache_path   /app/nginx/fastcgi_cache levels=2:2 keys_zone=two:200m inactive=1d max_size=30g;
 
        server {
                listen          80;
                server_name     www.demo.cn;
                root            /app/projects/demo;
 
                #设置索引文件和URL重写
                location / {
                        index index.html index.php; ## Allow a static html file to be shown first
                        try_files $uri $uri/ @handler; ## If missing pass the URI to Magento's front handler
                        expires 30d; ## Assume all files are cachable
                }
 
				#屏蔽一些目录,防止被外部访问
                ## These locations would be hidden by .htaccess normally
                location /app/                  { deny all; }
                location /includes/             { deny all; }
                location /lib/                  { deny all; }
                location /media/downloadable/   { deny all; }
                location /pkginfo/              { deny all; }
                location /report/config.xml     { deny all; }
                location /var/                  { deny all; }
 
				#将错误报告加个密码保护
                location /var/export/ { ## Allow admins only to view export folder
                                auth_basic                                   "Restricted"; ## Message shown in login window
                                auth_basic_user_file htpasswd; ## See /etc/nginx/htpassword
                                autoindex                                                on;
                }
				#禁止访问.htaccess文件
                location  /. { ## Disable .htaccess and other hidden files
                        return 404;
                }
				#用来进行URL重写
                location @handler { ## Magento uses a common front handler
                        rewrite / /index.php;
                }
				#转发.php文件的请求
                location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
                        rewrite ^(.*.php)/ $1 last;
                }
				#将php请求传递到后端php-fpm CGI程序,端口是9000
                location ~ .php$ { ## Execute PHP scripts
                        if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
 
                        expires         off; ## Do not cache dynamic content
                        fastcgi_pass    127.0.0.1:9000;
                        #fastcgi_param  HTTPS $fastcgi_https;
                        fastcgi_param   SCRIPT_FILENAME  $document_root$fastcgi_script_name;
                        fastcgi_param   MAGE_RUN_CODE default; ## Store code is defined in administration > Configuration > Manage Stores
                        fastcgi_param   MAGE_RUN_TYPE store;
                        include                                fastcgi_params; ## See /etc/nginx/fastcgi_params
                }
				#这里是禁止访问SVN信息的配置
                location ~ ^(.*)\/\.svn\/{
                        deny all;
                }
        }
}

Magento备忘-通过某一个字段来Load对象

Magento提供了灵活的方式去获取一个对象,比如说Load、比如说Collection,等。。。 我们今天说的是Load函数。

很多人将表的主键值传到Mage_Core_Model_Abstract的load函数中去获取对象,而要通过表里面的某一个字段值来获取呢?

看下Load函数:

    /**
     * Load object data
     *
     * @param   integer $id
     * @return  G_Core_Model_Abstract
     */
    public function load($id, $field=null)
    {
        $this->_beforeLoad($id, $field);
        $this->_getResource()->load($this, $id, $field);
        $this->_afterLoad();
        $this->setOrigData();
        $this->_hasDataChanges = false;
        return $this;
    }

其实Load函数本身就支持传入某个字段,即通过某个字段去获取对象。

便于理解,我举个实际例子,通过Coupon Code来获取Coupon对象:

$coupon = Mage::getModel('salesrule/coupon')->load('discount50%off','code');

Magento随笔-关于SalesRule模块的问题

Magento的购物车促销规则和商品促销规则,看起来确实强大。乍一看强大得让人惊叹,不过只是浮云。为什么?因为你会发现,他无法做很多实际的促销活动。

我就拿我所在的服装行业为例:

第一,只能购物车中单个商品进行促销配置,无法进行组合促销。

我们通常会有“买两条牛仔裤,T恤衫50%折扣”。试问如何用Magento实现? 注意两条牛仔裤是不同款式的。因为几乎不会有顾客同时买同样一条牛仔库(同尺码、同颜色,即同SKU)。估计这个规则卖卖鸡蛋白菜还差不多。

第二,Best Deal不支持,只能用排序和是否停止匹配下一个规则来设置Rule。

什么意思呢?就是最佳折扣方式,比如有一个A “Buy N of X for Z$off” 和 B “Buy N of X get Y at 50% off”两个促销规则同时存在购物车里,那么A、B的应用顺序不一样,最终金额是不一样的,而不是通过SORT简单的配置A在B前面就可以的。虽然不容易做,但是这是一个促销模块应该考虑到的问题。

第三,如果是可配置商品,那么规则只能匹配可配置商品,不能具体匹配到最终购买的简单商品。

直接看代码吧,代码在SalesRule_Model_Quote_Discount里面。看这里 “Child item discount we calculate for parent”

/**
 * Child item discount we calculate for parent
 */
if ($item-&gt;getParentItemId()) {
    continue;
}

无法匹配子商品。都是问题。。。不过这个问题可以通过简单修改SalesRule_Model_Rule_Condition_Product来实现。

    /**
     * Validate Product Rule Condition (Upgrade by Joshua for apply child product)
     *
     * @param Varien_Object $object
     * @return bool
     */
    public function validate(Varien_Object $object)
    {
        $product = G::getModel('catalog/product')
            ->load($object->getProductId())
            ->setQuoteItemQty($object->getQty())
            ->setQuoteItemPrice($object->getPrice())
            ->setQuoteItemRowTotal($object->getRowTotal());
		$result = parent::validate($product);
		if($result){
			return $result;
		}elseif(count($object->getChildren()>0)){
			foreach ($object->getChildren() as $child){
		        $product = G::getModel('catalog/product')
		            ->load($child->getProductId())
		            ->setQuoteItemQty($object->getQty())
		            ->setQuoteItemPrice($object->getPrice())
		            ->setQuoteItemRowTotal($object->getRowTotal());
				$result = parent::validate($product);
				if($result)return $result;
			}
		}else{
			return $result;
		}
    }

有朋友也在使用Magento开展他们业务,并津津乐道,也许真是行业差异吧。

Magento备忘-EAV商品表直接取某一字段值

比通过模型LOAD商品模型后再用getData取值快

G::getResourceModel('catalog/product')->getAttributeRawValue($entityId, $attribute, $store)

getAttributeRawValue函数参考

    /**
     * Retrieve attribute's raw value from DB.
     *
     * @param int $entityId
     * @param int|string|array $attribute atrribute's ids or codes
     * @param int|G_Core_Model_Store $store
     * @return bool|string|array
     */
    public function getAttributeRawValue($entityId, $attribute, $store)

Magento深入理解-Grid报错clause is ambiguous问题

我记得之前没少讲过Grid,今天在写Grid遇到这样一个错误,将解决办法分享下。

SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'increment_id' in where clause is ambiguous

这个错误怎么来的呢,关键是clause is ambiguous。

使用Grid必须要设置一个Collection,往往这个Grid需要联表查询,就是写join语句。请看下面例子:

    protected function _getCollectionClass()
    {
        return 'sales/order_shipment_grid_collection';
    }
 
    protected function _prepareCollection()
    {
        $collection = G::getResourceModel($this->_getCollectionClass());
        $collection->getSelect()
        			->joinLeft(array('o'=>'sales_flat_order'),'main_table.order_id = o.entity_id','grand_total')
        			->joinLeft(array('st'=>'sales_flat_shipment_track'),'main_table.order_id = st.order_id',array('carrier_code','number','shipped_time'));
 
        $this->setCollection($collection);
        return parent::_prepareCollection();
    }

这段例子是我改写后台配送模块时用到的。原来只是一个简单的表,因为需要跟COD结算、还要监督发货部门的效率。所以需要将订单金额、发货时间等等联表查询出来,问题出在shipment表有个increment_id字段,而关联的order表同样也有这个increment_id字段。

按下面的这样来配置Grid:

        $this->addColumn('increment_id', array(
            'header'    => G::helper('sales')->__('Shipment #'),
            'index'     => 'increment_id',
            'type'      => 'text',
        ));

本来我们这里的increment id是物流号,而订单里的increment id是订单号,打开页面,Grid可以正常显示,但是当尝试搜索物流号的时候就会报错了,就是上面的错误。
于是开始找哇,几乎看遍了后台所有的grid,就不信找不到,终于出现了这样一段代码:

        $this->addColumn('created_at', array(
            'header'    =>G::helper('reports')->__('Created At'),
            'width'     =>'170px',
            'type'      =>'datetime',
            'index'     =>'created_at',
            'filter_index'=>'main_table.created_at',
            'sortable'  =>false
        ));
 
        $this->addColumn('updated_at', array(
            'header'    =>G::helper('reports')->__('Updated At'),
            'width'     =>'170px',
            'type'      =>'datetime',
            'index'     =>'updated_at',
            'filter_index'=>'main_table.updated_at',
            'sortable'  =>false
        ));

请看G_Adminhtml_Block_Report_Shopcart_Abandoned_Grid这个文件。
原来Column可以设置filter_index,之前自己还尝试’index’=>’main_table.increament_id’等等,原来这样就可了,于是上面我改的代码变成了这样:

        $this->addColumn('increment_id', array(
            'header'    => G::helper('sales')->__('Shipment #'),
            'index'     => 'increment_id',
            'filter_index' =>'main_table.increment_id',
            'type'      => 'text',
        ));

爽~~过滤正常了~~ :)

Magento深入理解-原来将数据导出Excel&Csv是如此容易

在领教Magento后台Grid强大之后,今天又发现一个更简便的方法,可以将Grid快速导出到CSV或者Excel.

大家可看这个是后台Mage_Adminhtml_Sales_ShipmentController的一段代码,说到家还是Grid的强大,$grid可以直接调用getCsvFile或getCsvFile。

    /**
     * Export shipment grid to CSV format
     */
    public function exportCsvAction()
    {
        $fileName   = 'shipments.csv';
        $grid       = $this->getLayout()->createBlock('adminhtml/sales_shipment_grid');
        $this->_prepareDownloadResponse($fileName, $grid->getCsvFile());
    }
 
    /**
     *  Export shipment grid to Excel XML format
     */
    public function exportExcelAction()
    {
        $fileName   = 'shipments.xml';
        $grid       = $this->getLayout()->createBlock('adminhtml/sales_shipment_grid');
        $this->_prepareDownloadResponse($fileName, $grid->getExcelFile($fileName));
    }

Performance is Key! – Notes on Magento’s Performance

原文:http://www.magentocommerce.com/blog/comments/performance-is-key-notes-on-magentos-performance/

Magento’s performance is key.

在过去的几个月中,我们投入大量资源,诊断和优化Magento的性能。现在Magento 1.0的主要功能已经完成,我们很高兴能分享我们的工作和已实现Magento优化方式、和测试的结果。

当软件有了广泛的特点、功能和灵活性的表现,在性能方面肯定需要优化,Magento也没有例外。下面是一些性能优化的方法,在Magento的最新版本出现几个。

  • Top menu join queries rewritten, top menu block is cached now on per store view level for every active category
  • Added catalog indexes for layered navigation and search
  • Added dynamic merge and whitespace remove during JavaScript load
  • Footer block is cached
  • Implemented <remove name=”"> directive in layout xml to avoid instantiating of unwanted block objects, skipped left/right column blocks generation for pages with 1-column template</remove>
  • Most of sales order attributes became static and were moved to one raw table
  • Quote, quote address and quote items entities are stored separately
  • Greatly improved popular tags block generation time
  • Quote optimization for using in top links block and in the sidebar
  • Implemented caching API for using in Mage_Core_Model_Abstract descendant models
  • Removed unnecessary queries from catalog pages and homepage (e.g. reduced total number of database queries from 700 to 60 for homepage, and from 500 to 100 on product listing page on a database of 1000 products and 300 categories).

From our performance and load tests we have found that the latest Magento release outperforms version 0.8.17240 by almost double. Below we show a graph of one of the load tests we ran using Apache Benchmark (ab) comparing the two Magento versions. We experienced similar results throughout our tests and comparisons of the two versions.

image

DYI (Do it Yourself) Performance Enhancements

While we continue to improve Magento’s core performance, there are additional improvements that Magento users can implement to yield performance gains in a single-server environment:

  • Install a PHP opcode cache such as APC or XCache. These can deliver significant improvements to PHP’s responsiveness by caching PHP code in an intermediate bytecode format, which saves the interpreter from recompiling the PHP code for each and every request.
  • Make sure your Apache configuration has KeepAlives enabled. KeepAlives are a trick where multiple HTTP requests can be funneled through a single TCP connection. Since the setup of each TCP connection incurs additional time, this can significantly reduce the time it takes to download all the files (HTML, JavaScript, images) for a website.
  • Use a memory-based filesystem for Magento’s var directory. Magento makes extensive use of file-based storage for caching and session storage. The slowest component in a server is the hard drive, so if you use a memory-based filesystem such as tmpfs, you can save all those extra disk IO cycles by storing these temporary files in memory instead of storing them on your slow hard drive.
  • Modify the configuration for your MySQL server to take better advantage of your server’s RAM. Most Linux distributions provide a conservative MySQL package out of the box to ensure it will run on a wide array of hardware configurations. If you have ample RAM (eg, 1gb or more), then you may want to try tweaking the configuration. An example my.cnf is below, though you will want to consult the MySQL documentation for a complete list of configuration directives and recommended settings.

Example my.cnf:

image

Time to Cluster?

As any successful online retailer knows, a growing business means growing pains. If your store is a huge success, then you’ll undoubtedly require more horsepower to keep your customers happy. This means leaving the world of single-server websites and moving to a clustered environment with two or more servers.

There are varying ways to accomplish this, but a typical first step is to add more web servers and place them all behind a load balancer, which will distribute the load fairly among all web servers. This method is popular because (a) web servers are cheaper than database servers; and (b) there’s really no limit to the amount of web servers you can add.

Note: One current limitation in Magento is that there is no official method to propagate catalog images to each web node. If you’re not comfortable setting up some sort of facility to do this, then you may want to hire a professional or try a different method of scaling.

A second method involves a performance tactic called “database replication.” When using replication, you will have two or more database servers in your cluster. One will be the “master” and the rest will be called “slaves.” The master is the only database server that accepts any sort of write-based queries. These write queries are then replicated by each of the slaves in real-time (or very close to it). The advantage of this setup is that Magento can issue read queries to any of the slave servers, saving all the write queries for the master database. A database is traditionally a difficult component to scale horizontally, so replication is a happy compromise.

The initial setup and configuration for MySQL replication is out of the scope of this document, but we can refer you to the experts. Here is a tutorial that explains all the details.

Once you have MySQL replication functioning, configuring Magento to use multiple database servers is a relatively simple task. The only file you will have to edit is app/etc/local.xml. An example is shown below. As you can see, there are two database connections configured, one called default_setup and one called default_read. The default_setup connection will be used for all write-based queries, and the default_read connection will be used for all read-based queries.

Example app/etc/local.xml:

image

This article has only covered a few of the well-known tactics for improving site performance. However, every website’s scenario is slightly different, so it’s often worth hiring a professional to appraise the needs of your site and provide you with possible upgrade options. But if you’re comfortable with Linux and confident when working with configuration files, try out a few of our suggestions above. You may be pleasantly surprised.

Magento再度发力-使用程序模型(Model)创建商品

我们的业务有个需求是从另一个库中导出数据,然后同步到Magento数据库中。之前同事研究过模拟post提交的方式,可以成功,但是速度很慢。后来同事研究过dataflow导入,发现父子商品无法关联。今晚我要使用模型去创建父子关联商品,此篇文章介绍如何创建父商品、创建子商品及如何关联父子商品。

作者:精东
转载请留名

一、第一个目标,创建父商品。
首先我打段原始数据:

Array
(
    [pool_id] => 1
    [item_parent] => 122083
    [item] => 150009417
    [ean] => 1400001001072
    [item_description] => TESTELC
    [color_id] => 10115
    [color_description] => PAVEMENT
    [size_id] => M38_0001
    [size_description] => 1
    [season_id] => 6
    [season_description] => Fall
    [phase_id] => 5
    [phase_description] => Basics
    [weight] => 11.2
    [pack_factor] => 24
    [unit_weight] => 0.466667
    [regular_unit_retail] => 46.99
    [selling_retail_currency] => CNY
    [division_number] => 116
    [division_description] => BODY
    [department_number] => 1166
    [department_description] => WOMENS LOUNGE
    [class_number] => 6
    [class_description] => JACKETS
    [subclass_number] => 1
    [subclass_description] => SLVLS JK
    [zh_item_title] => 
    [zh_color_description] => 
    [zh_romance_copy] => 
    [create_datetime] => 2010-05-05 03:53:33
    [last_update_datetime] => 2010-05-19 21:51:24
    [is_deleted] => 0
    [last_deleted_at] => 0000-00-00 00:00:00
    [is_synchronized] => 0
    [last_synchronized_at] => 0000-00-00 00:00:00
    [status] => 0
)

字段介绍:首先说我是做服装站点的,已经有三年时间。从数据看出item_parent是商品的style,也就是服装的款式,下面还有颜色、尺码等,最小单位是SKU,也就是字段item。

我的目标是首先去通过item去产品表中查询是否有这个商品,如果有则更新,没有则新增,代码:

    	foreach($items as $item)
    	{
    		$pid = $product->getIdBySku($item->getData('item'));
    		if(!$pid){
    			$this->createNewProduct($item);
    		}else{
    			$this->updateProduct($item);
    		}
    	}

接下来写创建商品的方法,结果研究eav_attribute,可以看到以下字段是必添的。

接下来我创建父商品,请看函数createNewProduct:

	public function createNewProduct($item) {
 
		//create Parent Product
		$product = G::getModel ( 'catalog/product' );
		$defaultAttributeSetId = G::getModel('eav/entity_type')->loadByCode('catalog_product')->getDefaultAttributeSetId();
 
		/* @var $product G_Catalog_Model_Product */
		//check if there has parent product
		$parentId = $product->getIdBySku ( $item->getData ( 'item_parent' ) );
		if (! $parentId) {
			$product->setTypeId ( G_Catalog_Model_Product_Type::TYPE_CONFIGURABLE );
			$product->setAttributeSetId ( $defaultAttributeSetId );
			$product->setSku ( $item->getData ( 'item_parent' ) );
			$product->setHasOptions ( 1 );
			$product->setRequiredOptions ( 1 );
			$product->setPrice ( $item->getData ( 'regular_unit_retail' ) );
			$product->setName ( $item->getData ( 'zh_item_title' ) ? $item->getData ( 'zh_item_title' ) : $item->getData ( 'item_description' ) );
			$product->setDescription ( $item->getData ( 'zh_item_description' ) ? $item->getData ( 'zh_item_description' ) : $item->getData ( 'item_description' ) );
			$product->setShortDescription ( $item->getData ( 'zh_romance_copy' ) ? $item->getData ( 'zh_romance_copy' ) : $item->getData ( 'item_description' ) );
			$product->setTaxClassId ( 0 );
			$product->setVisibility ( G_Catalog_Model_Product_Visibility::VISIBILITY_BOTH );
			$product->setWeight ( $item->getData ( 'unit_weight' ) * 1000 );
			$product->setStatus ( 2 );
			$product->setStockData ( array ('is_in_stock' => 1 ) );
			$product->setCreatedAt ( strtotime ( 'now' ) );
			$product->save ();
		} else {
			//create child product
		}
		$instanceParent = $product->getTypeInstance ();
		/* @var $instanceParent G_Catalog_Model_Product_Type_Configurable */
		die ( get_class ( $instanceParent ) );
	}

需要注意的地方是:
setAttributeSetId,这里默认使用的是4,可以看eav_attribute_set这个表,4是catalog_product。

当然你如果不愿意使用固定数值,你也可以通过模型获得。

$defaultAttributeSetId = G::getModel('eav/entity_type')->loadByCode('catalog_product')->getDefaultAttributeSetId();

OK,写到这里,应该已经可以创建一个父商品了,看看你的数据库,再看看后台的商品列表。应该已经出现了这个父商品。函数中有些凌乱的debug语句,呵呵,下面会删除,这里是调试用。

二、创建子商品,有了父商品的经验,创建子商品相对比较简单。
直接看代码吧:

	public function createNewProduct($item) {
 
		//create Parent Product
		$product = G::getModel ( 'catalog/product' );
		$defaultAttributeSetId = G::getModel('eav/entity_type')->loadByCode('catalog_product')->getDefaultAttributeSetId();
 
		/* @var $product G_Catalog_Model_Product */
		//check if there has parent product
		$parentId = $product->getIdBySku ( $item->getData ( 'item_parent' ) );
		if (! $parentId) {
			$product->setTypeId ( G_Catalog_Model_Product_Type::TYPE_CONFIGURABLE );
			$product->setAttributeSetId ( $defaultAttributeSetId );
			$product->setSku ( $item->getData ( 'item_parent' ) );
			$product->setHasOptions ( 1 );
			$product->setRequiredOptions ( 1 );
			$product->setPrice ( $item->getData ( 'regular_unit_retail' ) );
			$product->setName ( $item->getData ( 'zh_item_title' ) ? $item->getData ( 'zh_item_title' ) : $item->getData ( 'item_description' ) );
			$product->setDescription ( $item->getData ( 'zh_item_description' ) ? $item->getData ( 'zh_item_description' ) : $item->getData ( 'item_description' ) );
			$product->setShortDescription ( $item->getData ( 'zh_romance_copy' ) ? $item->getData ( 'zh_romance_copy' ) : $item->getData ( 'item_description' ) );
			$product->setTaxClassId ( 0 );
			$product->setVisibility ( G_Catalog_Model_Product_Visibility::VISIBILITY_BOTH );
			$product->setWeight ( $item->getData ( 'unit_weight' ) * 1000 );
			$product->setStatus ( 2 );
			$product->setStockData ( array ('is_in_stock' => 1 ) );
			$product->setCreatedAt ( strtotime ( 'now' ) );
			$product->save ();
		} else {
			$product->setTypeId ( G_Catalog_Model_Product_Type::TYPE_SIMPLE );
			$product->setAttributeSetId ( $defaultAttributeSetId );
			$product->setSku ( $item->getData ( 'item' ) );
			$product->setHasOptions ( 1 );
			$product->setRequiredOptions ( 1 );
			$product->setPrice ( $item->getData ( 'regular_unit_retail' ) );
			$product->setName ( $item->getData ( 'zh_item_title' ) ? $item->getData ( 'zh_item_title' ) : $item->getData ( 'item_description' ) );
			$product->setDescription ( $item->getData ( 'zh_item_description' ) ? $item->getData ( 'zh_item_description' ) : $item->getData ( 'item_description' ) );
			$product->setShortDescription ( $item->getData ( 'zh_romance_copy' ) ? $item->getData ( 'zh_romance_copy' ) : $item->getData ( 'item_description' ) );
			$product->setTaxClassId ( 0 );
			$product->setVisibility ( G_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE );
			$product->setWeight ( $item->getData ( 'unit_weight' ) * 1000 );
			$product->setStatus ( 2 );
			$product->setStockData ( array ('is_in_stock' => 1 ) );
			$product->setCreatedAt ( strtotime ( 'now' ) );
			$product->save ();
		}
		$instanceParent = $product->getTypeInstance ();
		/* @var $instanceParent G_Catalog_Model_Product_Type_Configurable */
		die ( get_class ( $instanceParent ) );
	}

此时创建的子商品还是个超级简单的商品,但是我们的业务目的已经实现了。我还要给子商品设置一些属性,例如颜色、尺码、自定义颜色等。

未完,待续~~~~~~~~~~~~~~