Magento has a built-in API that has many features, but there are scenarios where the present features are simply not enough. If you need to build an external app that communicates with Magento via the aforementioned API, you will certainly discover its limitations.
Luckily, the API can be extended by writing a custom module that overrides the default API class and adds the responses we need.
In this tutorial, we’re going to create a custom module called “Upment ApiX” which extends the sales order info in Magento API.
First of all, we’ll need to create Upment_ApiX.xml file and place it in the app/etc/modules directory.
<?xml version="1.0"?>
<config>
<modules>
<Upment_ApiX>
<active>true</active>
<codePool>local</codePool>
</Upment_ApiX>
</modules>
</config>
That simply informs Magento that our module is enabled, and it’s in the local code pool. So, let’s create the directory our module will reside in. Since we defined the pool as local, and plugin name as Upment ApiX, the our main directory is app/code/local/Upment/ApiX.
Since we’re extending the sales order API, we’ll have to rewrite the classes that are responsible for API responses. We’ll define that in our etc/config.xml file (that’s relative to our main directory). It goes like this:
<?xml version="1.0"?>
<config>
<global>
<models>
<sales>
<rewrite>
<order_api>Upment_ApiX_Model_Sales_Order_Api</order_api>
<order_api_v2>Upment_ApiX_Model_Sales_Order_Api_V2</order_api_v2>
</rewrite>
</sales>
</models>
</global>
</config>
We have now ordered Magento to use our classes instead of the built-in Magento API for sales orders. Notice that we had to define two classes – first one for API v1, and the second one for API v2. Do not worry about it too much, we’ll cover it shortly.
Now would be a good time to write the class itself. So, let’s create our model for API v1. We’ve defined the class as Upment_ApiX_Model_Sales_Order_Api so we’ll place it in Model/Sales/Order/Api.php:
<?php
class Upment_ApiX_Model_Sales_Order_Api extends Mage_Sales_Model_Order_Api {
protected $result = array();
}
// EOF
As you can see, it doesn’t do much yet. We’ve added the protected $result array to store our response, and now we’re going to add our new, extended function for getting the order info inside the class:
public function info($orderIncrementId) {
$order = $this->_initOrder($orderIncrementId);
$array = $order->toArray();
$this->_newarray($array, $this->result);
$message = Mage::getModel('giftmessage/message');
$gift_message_id = $array['gift_message_id'];
if(!is_null($gift_message_id)) {
$message->load((int)$gift_message_id);
$array_message=$message->toArray();
$this->_newarray($array_message, $this->result['gift_message_obj']);
}
}
We added the gift message to our API response. You’ll notice that we’re using the _newarray function. That’s a custom function that we will create to recursively go through the data and create arrays where possible:
protected function _newarray($data, &$res) {
foreach( $data as $key => $value ) {
if( !is_array($value) ) {
$new_array = @unserialize($value);
if ($value === 'b:0;' || $new_array !== false) {
$value = $new_array;
}
}
if( is_array($value) ) {
$this->_newarray($value, $res[$key]);
} else {
if ($value != '') $res["$key"] = "$value";
}
}
}
As you can see, the function goes through array, unserializing where possible in order to create new arrays from serialized data and return that in response.
So, all of this was for API v1. What about API v2? Well, first of all, we need to extend the API v2 class. We defined our new class name as Upment_ApiX_Model_Sales_Order_Api_V2 in etc/config.xml so it goes to the Model/Sales/Order/Api/V2.php file:
<?php
class Upment_ApiX_Model_Sales_Order_Api_V2 extends Upment_ApiX_Model_Sales_Order_Api {
}
// EOF
That’s it. The class only takes the result from V1 and passes it on to V2 call. However, we do need to make a few more changes in other places.
First of all, let’s create our etc/wsdl.xml file and define additional response fields:
<?xml version="1.0" encoding="UTF-8"?>
<definitions
xmlns:typens="urn:{{var wsdl.name}}"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
name="{{var wsdl.name}}"
targetNamespace="urn:{{var wsdl.name}}">
<types>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:Magento">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"
schemaLocation="http://schemas.xmlsoap.org/soap/encoding/" />
<complexType name="salesOrderEntity">
<all>
<element
name="gift_message_obj"
type="typens:giftMessage"
minOccurs="0" />
</all>
</complexType>
<complexType name="giftMessage">
<all>
<element name="gift_message_id" type="xsd:string" minOccurs="0" />
<element name="customer_id" type="xsd:string" minOccurs="0" />
<element name="message" type="xsd:string" minOccurs="0" />
</all>
</complexType>
</schema>
</types>
</definitions>
We’ll have to do the same for etc/wsi.xml:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions
xmlns:typens="urn:{{var wsdl.name}}"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
name="{{var wsdl.name}}"
targetNamespace="urn:{{var wsdl.name}}">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:{{var wsdl.name}}">
<xsd:complexType name="salesOrderEntity">
<xsd:sequence>
<xsd:element name="gift_message_obj" type="typens:giftMessage" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="giftMessage">
<xsd:sequence>
<xsd:element name="gift_message_id" type="xsd:string" minOccurs="0" />
<xsd:element name="customer_id" type="xsd:string" minOccurs="0" />
<xsd:element name="message" type="xsd:string" minOccurs="0" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
</wsdl:definitions>
What we’ve done there is that we extended the default Magento response definitions by adding our gift message fields. Note that we didn’t have to include the entire wsdl or wsi, just the things we added; Magento will merge our definitions with its own.
That’s it, we have successfully extended the Magento API call for sales order info. You can use this method to extend responses for any other API call, the principle is the same. Just don’t forget to flush the cache; otherwise, it may not work immediately.