使用xpath和varien_object运行模块xml文件中指定的方法
去年,我们为用户开发了一些定制的EPR系统。客户的文件中指出他们需要运行一些在config.xml中定义的方法,在出口订单的时候用方法代码作为ID。很快,根据订单的付款代码他们想在出口订单时添加一些自定义计算。如果你对我们如何实现的感兴趣,那么继续阅读吧。
举例会让解释变得简单。首先创建我们的config.xml,最后我们将让Magento呼应我们的模块。
Step 1: Creating module’s configuration(创建模型配置)
这里只是个简单的示例代码,你可以用它创建app/code/local/Alwayly/XmlMethodCall/etc/config.xml
< ?xml version="1.0"?>
<config>
<modules>
<alwayly_xmlmethodcall>
<version>1.0.0.0</version>
</alwayly_xmlmethodcall>
</modules>
<global>
<xml_method_call>
<payment_checkmo>
<name>Check / Money order </name>
<code>checkmo</code>
<add>
<model>alwayly_xmlmethodcall/checkmoAddVal</model>
<method>addValue</method>
</add>
<return>
<model>alwayly_xmlmethodcall/checkmoGetCod</model>
<method>getCode</method>
</return>
</payment_checkmo>
</xml_method_call>
<xml_method_call>
<payment_ccsave>
<name>Credit Card (saved) </name>
<code>ccsave</code>
<add>
<model>alwayly_xmlmethodcall/ccsaveAddVal</model>
<method>addValue</method>
</add>
<return>
<model>alwayly_xmlmethodcall/ccsaveGetCod</model>
<method>getCode</method>
</return>
</payment_ccsave>
</xml_method_call>
<models>
<alwayly_xmlmethodcall>
<class>Alwayly_XmlMethodCall_Model</class>
<resourcemodel>alwayly_xmlmethodcall_mysql4</resourcemodel>
</alwayly_xmlmethodcall>
</models>
</global>
<frontend>
<routers>
<alwayly_xmlmethodcall>
<use>standard</use>
<args>
<module>Alwayly_XmlMethodCall</module>
<frontname>xmlmethodcall</frontname>
</args>
</alwayly_xmlmethodcall>
</routers>
</frontend>
</config>
深入研究下xml_method_call结点和全球结点的第一子节点。你会看到两兄弟有同样的名字, xml_method_call结点。
让我们描述下下一个xml块:
<payment_checkmo>
<name>Check / Money order </name>
<code>checkmo</code>
<add>
<model>alwayly_xmlmethodcall/checkmoAddVal</model>
<method>addValue</method>
</add>
<return>
<model>alwayly_xmlmethodcall/checkmoGetCod</model>
<method>getCode</method>
</return>
</payment_checkmo>
- payment_checkmo 包含一些数据的唯一结点
- name 这个唯一结点的名字,与代码无关
- code 支付方式的代码(id)
- add,return 两种方法定义他们应该调用的东西(模块/模型和方法调用的定义)
现在我希望你对我们需要怎么实现有一个清晰的认识。在订单出口的时候我们调用一些方法做计算并返回结果。要求是方法需要是可配置的,这样非开发人员可以通过配置文件来改变它们。当然,你可以在system.xml中做到这点。
Step 2: Creating module’s models, described in config.xml(创建模块的模型,在config.xml中写描述)
Create files:
- – app/code/local/Alwayly/XmlMethodCall/Model/CheckmoAddVal.php
- – app/code/local/Alwayly/XmlMethodCall/Model/CheckmoGetCod.php
- – app/code/local/Alwayly/XmlMethodCall/Model/CcsaveAddVal.php
- – app/code/local/Alwayly/XmlMethodCall/Model/CcsaveGetCod.php
分别添加下面的代码到对应的文件中:
< ?php
/**
*
*/
class Alwayly_XmlMethodCall_Model_CheckmoAddVal extends Mage_Core_Model_Abstract
{
public function addValue()
{
return 1;
}
}
< ?php
/**
*
*/
class Alwayly_XmlMethodCall_Model_CheckmoGetCod extends Mage_Core_Model_Abstract
{
public function getCode()
{
return 'a';
}
}
< ?php
/**
*/
class Alwayly_XmlMethodCall_Model_CcsaveAddVal extends Mage_Core_Model_Abstract
{
public function addValue()
{
return 2;
}
}
< ?php
/**
*
*/
class Alwayly_XmlMethodCall_Model_CcsaveGetCod extends Mage_Core_Model_Abstract
{
public function getCode()
{
return 'b';
}
}
因为是一个简单的教学示例,我们将只创建控制器并在里面的几个列数组里的订单。
Step 3: Creating controller(创建控制器)
< ?php
/**
*
*/
class Alwayly_XmlMethodCall_IndexController extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
$orders = array();
$orders[] = array (
'order_no' => 101,
'method' => 'checkmo',
'amount' => 99
);
$orders[] = array (
'order_no' => 102,
'method' => 'ccsave',
'amount' => 100
);
$orders[] = array (
'order_no' => 101,
'method' => 'checkmo',
'amount' => 199
);
foreach ($orders as $row) {
$orderNo = $row['order_no'];
$conf = Mage::getSingleton('core/config')->init()
->getXpath('global/xml_method_call//code[.="' . $row['method'] . '"]/..');
if ($conf) {
$conf = new Varien_Object(current($conf)->asArray());
$add = new Varien_Object($conf->getAdd());
$code = new Varien_Object($conf->getReturn());
if (method_exists(Mage::getModel($add->getModel()), $add->getMethod())) {
$amountValue = $row['amount'] + Mage::getModel($add->getModel())->{$add->getMethod()}();
}
if (method_exists(Mage::getModel($code->getModel()), $code->getMethod())) {
$codeValue = Mage::getModel($code->getModel())->{$code->getMethod()}();
}
} else {
//throw an error
die("or exit... or something goes wrong...");
}
echo "<pre>" . PHP_EOL;
echo 'ID: ' . $orderNo . PHP_EOL;
echo 'VALUE: ' . $amountValue . PHP_EOL;
echo 'CODE: ' . $codeValue . PHP_EOL;
}
print_r($orders);
}
}
首先,我们创建了包含一些$orders里数据的订单集合。这可能是一个真实的集合,但是现在为了简化,我决定用个简单的二维数组。
下一个重要的部分是:
$conf = Mage::getSingleton('core/config')->init()->getXpath('global/xml_method_call//code[.="' . $row['method'] . '"]/..');
如你所见,我们调用code/config模型里的XPath。如果你不知道this ->getXpath(‘global/xml_method_call//code[.=”‘ . $row[‘method’] . ‘”]/..’)的意思,那么你可以去w3schools/XPath学些新东西。
我们将要实例化$conf对象,把xml_method_call作为根节点。我们不知道哪一个是它,但我们知道方法的代码并可以在config.xml搜索它。
"//"意味着同一级别。比temp结点深,确认你所能找到的所有结点然后挑选出含有你所需值的那个。
"/.."意味着返回当前位置的上一级结点,获取你想要的xml_method_call结点。这样所有事情就变得简单了。
下一个有趣的部分是:
$conf = new Varien_Object(current($conf)->asArray());
$add = new Varien_Object($conf->getAdd());
$code = new Varien_Object($conf->getReturn());
设置我们的$conf, $add和$code作为Varien_Object实例(我们将有自己的getter和setter)。
最后确认我们的方法是否存在。如果存在就在显示器上打印出结果。
那么让Magento配置对象呼应我们的模块,接着访问我们的控制器。
Step 4: Magento, we are here!(Magento,我们在这儿!)
用下面的代码创建文件app/etc/modules/Alwayly_Xmlmethodcall.xml
<?xml version="1.0"?>
<config>
<modules>
<Alwayly_XmlMethodCall>
<active>true</active>
<codePool>local</codePool>
</Alwayly_XmlMethodCall>
</modules>
</config>
Step 5: Visit something like: http://magento1510.loc/index.php/xmlmethodcall(访问类似http://magento1510.loc/index.php/xmlmethodcall的地址)
你会看到类似这样的结果:
ID: 101
VALUE: 100
CODE: a
ID: 102
VALUE: 102
CODE: b
ID: 101
VALUE: 200
CODE: a
Array
(
[0] => Array
(
[order_no] => 101
[method] => checkmo
[amount] => 99
)
[1] => Array
(
[order_no] => 102
[method] => ccsave
[amount] => 100
)
[2] => Array
(
[order_no] => 101
[method] => checkmo
[amount] => 199
)
)
我希望你们中的一些人能看到如何使用Varien_Object以及使用XPath表达式会让事情变得多么有趣。
电商网站开发服务。