Archive for the ‘ PHP ’ Category

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 ) );
	}

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

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

MageCommerce(Magento中文版) 招募代码贡献者

我们的目标:
为了能够让国人早日使用上真正的Magento中文版。

QQ群:106248975(请谅解,这里只接受开发者,暂时不接受使用用户。)

警告正在使用由CosmoCommerce开发的Magento支付宝(Alipay)&快钱(99bill)支付插件的用户

今天在看Magento官网的免费版支付宝(Alipay)支付和快钱(99bill)支付插件,首先感谢开发者的共享精神,但发现一个严重问题,而且警告现在正使用这两个插件的用户。它们极其不安全,在后端接收支付网关的相关程序有严重安全漏洞,可以篡改订单的支付状态到已支付,实际用户并未支付。如果插件确认是下面列的版本,建议立即
停止使用。

        <CosmoCommerce_Alipay>
            <version>0.9.1</version>
        </CosmoCommerce_Alipay>
        <CosmoCommerce_Cosmo99Bill>
            <version>0.9.0</version>
        </CosmoCommerce_Cosmo99Bill>

直觉告诉我在MAGENTO CONNECT里由CosmoCommerce写的支付网关都有问题,没有时间做进一步验证。

缺陷解释,一般我们在开发支付接口的时候有验签和解签的动作,一般用户可以理解它为加密与支付网关之间的数据。而在接收支付网关的数据时我们必须做的两步:
第一是验签,即严正这个请求数据是否由网关发出的,不然任何一个人都可以更改订单状态。
第二是去重处理,即支付网关有可能重复发送支付结果给你的网站,如果不做去重处理,已经到已完成的订单很可能又会回到处理中状态(取决于支付插件的配置—支付成功后的订单状态)。

而这两个插件的接收参数端没有对以上两点做任何的处理。结论是,任何一个人都可以修改订单状态,已经到已完成的订单又会回到处理中状态,有经过实际测试!简单到访问这个URL就可以:

https://www.somestore.com/cosmo99bill/payment/notify/?reference=100000009
http://www.somestore.com/alipay/payment/notify/?trade_status=TRADE_FINISHED&out_trade_no=100000008

我带大家看一段代码,用来解释,请打开这个文件 app/code/community/CosmoCommerce/Alipay/controllers/PaymentController.php
下面这段代码就是对应的上面的URL(http://www.somestore.com/alipay/payment/notify/?trade_status=TRADE_FINISHED&out_trade_no=100000008)

    public function notifyAction()
    {
        //WEMVC:这里是获取参数代码
        if ($this->getRequest()->isPost())
        {
            $postData = $this->getRequest()->getPost();
            $method = 'post';
 
 
        } else if ($this->getRequest()->isGet())
        {
            $postData = $this->getRequest()->getQuery();
            $method = 'get';
 
        } else
        {
            return;
        }
 
        //WEMVC:问题就在这里,开发者没有经过任何验签过程直接改了订单状态。同时也没有去重处理。
        if ($postData['trade_status'] == "TRADE_FINISHED")
        {
            $order = Mage::getModel('sales/order');
            $order->loadByIncrementId($postData['4']);
            //$order->setAlipayTradeno($postData['trade_no']);
            $order->setStatus(Mage_Sales_Model_Order::STATE_PROCESSING);
            // $order->sendNewOrderEmail();
            $order->addStatusToHistory(
            $order->getStatus(),
            Mage::helper('alipay')->__('买家已付款, 等待卖家发货。'));
            try
            {
                $order->save();
            } catch(Exception $e)
            {
                ;
            }
 
 
        }
 
        return;
    }

Magento如何重写或新建后台的页面

最开始的时候我们如果想写一个后台的控制器,是简单地依照前台的写法新建一个控制器,并继承Mage_Adminhtml_Controller_Action。但是这样有个缺点,就是你后台和前台没法分家,还有就是后台的URL会很怪,看下面例子:

MAGENTO自带的都是:

http://www.wemvc.com/index.php/admin/customer/index/key/59245faf7159619f335655fd7f8197e9/

而你的很可能是这样的:

http://www.wemvc.com/index.php/customer/list/index/key/59245faf7159619f335655fd7f8197e9/

是不是很怪,相信你也想与MAGENTO保持一致,请看下面的方法。
阅读全文

Magento关闭Google Checkout模块受到的启发

今天在关闭Google Checkout模块的时候发现在CHECKOUT ONEPAGE遇到了问,就是明明已经关闭了,可结算页面还在加载GOOGLE CHECKOUT里的类。
由于我是在Mage_All里面直接代码级别关闭的,所以页面报错。

Warning: include(Mage/Googlecheckout/Model/Payment.php): failed to open stream: No such file or directory  in /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/lib/Varien/Autoload.php on line 93
 
#0 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/lib/Varien/Autoload.php(93): mageCoreErrorHandler(2, 'include(Mage/Go...', '/home/joshua/Ze...', 93, Array)
#1 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/lib/Varien/Autoload.php(93): Varien_Autoload::autoload()
#2 [internal function]: Varien_Autoload->autoload('Mage_Googlechec...')
#3 [internal function]: spl_autoload_call('Mage_Googlechec...')
#4 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Config.php(1204): class_exists('Mage_Googlechec...')
#5 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/Mage.php(432): Mage_Core_Model_Config->getModelInstance('googlecheckout/...', Array)
#6 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Payment/Helper/Data.php(71): Mage::getModel('googlecheckout/...')
#7 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Payment/Block/Form/Container.php(117): Mage_Payment_Helper_Data->getStoreMethods('1', Object(Mage_Sales_Model_Quote))
#8 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Payment/Block/Form/Container.php(44): Mage_Payment_Block_Form_Container->getMethods()
#9 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Block/Abstract.php(218): Mage_Payment_Block_Form_Container->_prepareLayout()
#10 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(430): Mage_Core_Block_Abstract->setLayout(Object(Mage_Core_Model_Layout))
#11 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(446): Mage_Core_Model_Layout->createBlock('checkout/onepag...', 'checkout.paymen...')
#12 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(238): Mage_Core_Model_Layout->addBlock('checkout/onepag...', 'checkout.paymen...')
#13 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(204): Mage_Core_Model_Layout->_generateBlock(Object(Mage_Core_Model_Layout_Element), Object(Mage_Core_Model_Layout_Element))
#14 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(205): Mage_Core_Model_Layout->generateBlocks(Object(Mage_Core_Model_Layout_Element))
#15 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(205): Mage_Core_Model_Layout->generateBlocks(Object(Mage_Core_Model_Layout_Element))
#16 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/Layout.php(209): Mage_Core_Model_Layout->generateBlocks(Object(Mage_Core_Model_Layout_Element))
#17 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Controller/Varien/Action.php(343): Mage_Core_Model_Layout->generateBlocks()
#18 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Controller/Varien/Action.php(270): Mage_Core_Controller_Varien_Action->generateLayoutBlocks()
#19 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Checkout/controllers/OnepageController.php(165): Mage_Core_Controller_Varien_Action->loadLayout()
#20 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Controller/Varien/Action.php(418): Mage_Checkout_OnepageController->indexAction()
#21 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(254): Mage_Core_Controller_Varien_Action->dispatch('index')
#22 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Controller/Varien/Front.php(177): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http))
#23 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/code/core/Mage/Core/Model/App.php(304): Mage_Core_Controller_Varien_Front->dispatch()
#24 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/app/Mage.php(596): Mage_Core_Model_App->run(Array)
#25 /home/joshua/Zend/workspaces/DefaultWorkspace7/gap/index.php(80): Mage::run('default', 'store')
#26 {main}

后来通过报错信息寻找发现是在结算页面需要加载允许的结算方式,正常配置文件应该走/Payment/etc/config.xml里的默认配置,可是Mage毕竟不是完美的,发现在Sales的模块配置文件竟有这样一段:

        <payment>
            <googlecheckout>
                <active>1</active>
                <model>googlecheckout/payment</model>
                <title>Google Checkout</title>
            </googlecheckout>
        </payment>

这段配置本来应该在GoogleCheckout模块配置文件里的,我将其注释掉,OK了一切正常。

还有就是获取配置数据的getConfig方法,以往大家以为$path参数一定要写全,比如payment/googcheckout/active,其实你写开头的一部分也会有返回数据,你可以试试

Mage::getStoreConfig('payment');

你会发现,它返回的是一个多维数组。

Magento作为内容管理系统(cms)或开发框架使用

Magento框架设计的魅力实在是另我钦佩,所以把Magento其他模块都禁用掉了仅留下了Core和Cms模块,作为我的开发框架使用。试用了下,完美!

作为CMS可能Magento不是最好的,我们也不去争论它,只是我认为这样做更适合我的需求,或者说是适合作为我的开发框架使用。同时我要说的是这样禁用掉很多模块,后台留下的一些目录进去后会报错,这个要依照你自己的使用去修改。我相信能对我这篇文章感兴趣的人一定有很深的技术基础,所以请尽情发挥吧,Magento可以带给你无限的可能。

当前使用版本Magento 1.4.1
作者:精东(转载请留下作者信息)
阅读全文

重写Mage_Core_Model_Cache遇到的问题

今天一直在尝试复写Magento的Mage_Core_Model_Cache类。最后发现magento首先加载cache模型,在config之前,所以通过模块下的etc/config.xml是不成的了。

说实话magento自带的缓存类很不错,支持大多数缓存机制。再往深说些,Magento其实用的就是Zend_Cache,呵呵,也不是自己的东西。有个鸡肋或我个人认为没啥意义的database cache,是自己的Varien_Cache_Backend_Database。

Magento英文原版用户手册分享下载

分享Magento英文原版用户手册。

点击下载

Magnto获取当前店铺和店铺配置的方法

开发中常常用到获取当前店铺的ID或者获取当前店铺的配置。其实非常的简单,看代码:

1、获取店铺

$store = Mage::app()->getStore();

你可以print一下$store,它是Mage_Core_Model_Store对象,获取数据可以通过下面代码获取

$store = Mage::app()->getStore()->getData();

2、获取当前店铺配置的配置

$value = Mage::app()->getStore()->getConfig($path)

很简单。。。

作者:精东

magento – 计划任务(cron job)在magento中的作用和使用教程

计划任务(cron job)是Magento系统中一个很有用甚至可以说必须使用的功能,而最近在网上跟人聊天发现很多Magento的使用者不知道这个功能或者知道却认为可有可无,我在这里建议各位Magento的使用者,把这个功能使用起来吧。

在之前关于Newsletter的那篇博文我有讲到,要使新闻能按设定的时间自动发送,就必须设置好计划任务(cron job)。计划任务(cron job)简单的来说就是在系统中每隔一段时间来重复操作一件事,比如每隔多少时间清理日志,比如每天提交Sitemap给google等等。
阅读全文