Edit: Found a better way, see Solution 2 below
As mentioned in the comment, the SOAP API is the way to go.
Solution 1:
Suds worked for me with slight modification (Usage of Titanium.Network.HTTPClient
instead of XMLHttpRequest
), but it does not much more than creating a SOAP envelope for the call and returning the whole XML response.
Proof-of-Concept implementation, using jQuery Deferred for request chaining:
Service.MagentoClient = function()
{
var self = this;
var suds = new SudsClient({
endpoint : "http://the-magento-host/api/v2_soap/",
targetNamespace : "urn:Magento",
});
self.login = function() {
var deferred = new $.Deferred();
var args = {
username : 'the-username',
apiKey: 'the-api-key'
};
suds.invoke("login", args, function(xmlDoc) {
self.sessionId = $(xmlDoc).find("loginReturn").text();
deferred.resolve({});
//TODO reject if no sessionid returned
});
return deferred;
};
self.setStatus = function(orderId, status, comment, notify) {
var deferred = new $.Deferred();
if (!self.sessionId) {
deferred.reject({ error: 'Login not successful.' });
return;
}
var args = {
sessionId : self.sessionId,
orderIncrementId : orderId,
status : status,
comment : comment,
notify : notify
}
suds.invoke("salesOrderAddComment", args, function(xmlDoc) {
var success = $(xmlDoc).find("salesOrderAddCommentResponse").text();
if (success) {
deferred.resolve({});
} else {
deferred.reject({ error: 'Update not successful.' });
}
});
return deferred;
};
};
Usage example:
var magento = new Service.MagentoClient();
magento.login().then(function() {
magento.setStatus('100000029', 'complete', 'soap test');
}).then(function() {
alert('Update successful');
}, function(reject) {
alert('Update failed: ' + reject.error);
});
Solution 2:
Turned out that writing an own API adapter can be really easy. With the example of this core-hack (dead link) I was able to write a clean module for a JSON-RPC adapter based on Zend_Json_Server
. It uses the same Authentication and ACL as the SOAP and XML-RPC APIs.
To use the entry point /api/jsonrpc
, the new controller has to be added to the api
route:
<config>
<frontend>
<routers>
<api>
<args>
<modules>
<my_jsonrpc before="Mage_Api">My_JsonRpc_Api</my_jsonrpc>
</modules>
</args>
</api>
</routers>
</frontend>
</config>
Update 02/2015: The above link is dead now, so I open sourced my JSON-RPC adapter as a complete extension: https://github.com/sgh-it/jsonrpc
My JS client now looks like this (again with JQuery.Deferred, but no additional 3rd party libraries for the API):
/**
* Client for the Magento API
*/
Service.MagentoClient = function()
{
var self = this;
/**
* @param string method the remote procedure to call
* @param object params parameters for the RPC
* @param callback onSuccess callback for successful request. Expects one parameter (decoded response object)
* @param callback onError callback for failed request. Expects one parameter (error message)
*
* @return void
*/
self.jsonRpc = function(method, params, onSuccess, onError) {
var request = {
method : method,
params : params,
jsonrpc : "2.0",
id : 1
};
var options = {
entryPoint : config.magentoClient.entryPoint,
method: 'post',
timeout: config.magentoClient.timeout
};
var httpClient = Titanium.Network.createHTTPClient();
httpClient.onload = function(e) {
try {
var response = JSON.parse(this.responseText);
} catch (jsonError) {
return onError(jsonError);
}
if (response.error) {
if (response.error.code == 5) { // session expired
self.sessionId = null;
}
return onError(response.error.message);
}
onSuccess(response);
};
httpClient.onerror = function(e) {
onError(e.error + '; Response:' + this.responseText);
};
httpClient.setTimeout(options.timeout);
if (httpClient.open(options.method, options.entryPoint)) {
httpClient.setRequestHeader("Content-type", "application/json");
httpClient.send(JSON.stringify(request));
} else {
onError('cannot open connection');
}
}
/**
* Retrieve session id for API
*
* @return JQuery.Deferred deferred object for asynchronous chaining
*/
self.login = function() {
var deferred = new $.Deferred();
if (self.sessionId) {
deferred.resolve();
return deferred;
}
var loginParams = config.magentoClient.login;
try {
self.jsonRpc('login', loginParams, function(response) {
if (response && response.result) {
self.sessionId = response.result;
deferred.resolve();
} else {
deferred.reject('Login failed.');
}
}, function(error) {
deferred.reject(error);
});
} catch (rpcError) {
deferred.reject(rpcError);
}
return deferred;
};
/**
* Updates order states in Magento
*
* @param string method name of the remote method
* @param object args arguments for the remote method
*
* @return JQuery.Deferred deferred object for asynchronous chaining
*/
self.call = function(method, args) {
var deferred = new $.Deferred();
if (!self.sessionId) {
deferred.reject('No session.');
return;
}
var callParams = {
sessionId : self.sessionId,
apiPath : method,
args : args
};
try {
self.jsonRpc('call', callParams, function(response) {
deferred.resolve(response.result);
}, function(error) {
deferred.reject(error);
});
} catch (rpcError) {
deferred.reject(rpcError);
}
return deferred;
};
};
Note that all methods after login are routed through call
. The method
parameter is something like sales_order.list
, the args
parameter an array or object with the method arguments.
Usage example:
var filters = [];
var magento = new Service.MagentoClient();
magento.login().then(function() {
magento.call('sales_order.list', [filters]).then(
function(orders) {
// do something with the response
}, function(error) {
alert('Magento API error: ' + error);
}
);
});
You need to overwrite Mage_Catalog_Block_Product_View_Type_Configurable class
#app/code/core/Mage/Catalog/Block/Product/View/Type/Configurable.php
public function getJsonConfig()
{
$config = Zend_Json::decode(parent::getJsonConfig());
$productsCollection = $this->getAllowProducts();
foreach ($productsCollection as $product) {
$productId = $product->getId();
$config['products_sku'][$productId]['sku'] = $product->getSku();
}
$jsonConfig = Zend_Json::encode($config);
return $jsonConfig;
}
[Updated]
#app/etc/modules/SR_Stackexchange.xml
<?xml version="1.0"?>
<config>
<modules>
<SR_Stackexchange>
<active>true</active>
<codePool>local</codePool>
</SR_Stackexchange>
</modules>
</config>
Create app/code/local/SR/Stackexchange/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<SR_Stackexchange>
<version>0.0.0.1</version>
</SR_Stackexchange>
</modules>
<global>
<blocks>
<stackexchange>
<class>SR_Stackexchange_Block</class>
</stackexchange>
<catalog>
<rewrite>
<product_view_type_configurable>SR_Stackexchange_Block_Product_View_Type_Configurable</product_view_type_configurable>
</rewrite>
</catalog>
</blocks>
</global>
</config>
Create app/code/local/SR/Stackexchange/Block/Product/View/Type/Configurable.php
class SR_Stackexchange_Block_Product_View_Type_Configurable extends Mage_Catalog_Block_Product_View_Type_Configurable
{
public function getJsonConfig()
{
$config = Zend_Json::decode(parent::getJsonConfig());
$currentProduct = $this->getProduct();
$config['sku'] = $currentProduct->getSku();
$productsCollection = $this->getAllowProducts();
foreach ($productsCollection as $product) {
$productId = $product->getId();
$config['products_sku'][$productId]['sku'] = $product->getSku();
}
$jsonConfig = Zend_Json::encode($config);
return $jsonConfig;
}
}
Clear cache.
[Updated]
Suppose you have all config in var config. So you can display sku following way:
// For parent sku
console.log(config['sku'])
//You get all child sku
console.log(config['products_sku']);
//Specific child sku by product_id
var product_id = 294;
console.log(config['products_sku'][product_id]['sku'])
Best Answer
This depends on the Magento version. For version CE 1.7 the piece of code you wrote is commented out. In 1.6 and lower it's not.
Knowing this, I assume it's safe to comment the code and not worry about future upgrades.