I've been doing some work with the open source Magento web storesoftware, mostly to do with their XMLRPC API for our ReadyToShipsoftware. Inevitably, the requirement arised that couldn't besolved by the existing Magento API calls, so it was time to take alook at writing some code and building my own custom api call (assuggested by the Magento documentation).
Unfortunately, the documentation on doing so is kind of sketchy,so it was a slightly frustrating experience, not least because ofthe complexity of Magento's data structures. I've got a 'HelloWorld' API call working now though, and this post will have a dualpurpose: to help others who have been wrestling with the sameproblem, and to actually get it straight what I did to get itworking!
Before I start, can I just say that Mage::Log is your friend! Ifigured out a lot of what is going on here by throwingMage::Log("Bla bla") throughout the existing Magento code.
OK, first steps, here is the directory structure of my customfiles:
magento/ |-- app/ |-- code/ | |-- local/ | |-- CompanyName/ | |-- ModuleName/ | |-- etc/ | | |-- api.xml | | |-- config.xml | |-- Model/ | |-- ObjectModel/ | |-- Api.php |-- modules/ |-- etc/ |-- CompanyName_ModuleName.xml
A lot of directories for only 4 new files! But the directorystructure is important, as Magento makes use of strict namingconventions to find where it's class and config files are.
OK, let's tell Magento that we're writing a new module, and indoing so, where to find it. Here are the contents ofmagento/app/etc/modules/CompanyName_ModuleName.xml :
<?xml version="1.0"?> <config> <modules> <CompanyName_ModuleName> <active>true</active> <codePool>local</codePool> </CompanyName_ModuleName> </modules> </config>
Pretty simple, huh? From this piece of XML, Magento knows tolook in the magento/app/code/local/CompanyName/ModuleName directoryfor your module.
Next, let's take a look at the config file for our module. Hereare the contents ofmagento/app/code/local/CompanyName/ModuleName/etc/config.xml:
<?xml version="1.0" encoding="UTF-8"?> <config> <modules> <CompanyName_ModuleName> <version>0.1.0</version> </CompanyName_ModuleName> </modules> <global> <models> <test> <class>CompanyName_ModuleName_Model</class> </test> </models> </global> </config>
In this file we're defining an extra variable for our module (Isuspect the <modules> section couldgo in the CompanyName_ModuleName.xml file, actually, as all the XMLconfig is merged together), as well as telling Magento the baseclass name for the module (this is important to those constantlyhaving Magento look under the Mage/ directory for your class filesinstead of your company name, a problem I struggled with for quitea while).
Next is the definition of our API call, here are the contents ofmagento/app/code/local/CompanyName/ModuleName/etc/api.xml:
<?xml version="1.0"?> <config> <api> <resources> <resource_name translate="title" module="companyname_modulename"> <title>Title Of My Resource</title> <model>modulename/objectmodel_api</model> <methods> <methodName translate="title" module="companyname_modulename"> <title>Title Of My Method</title> </methodName> </methods> </resource_name> </resources> </api> </config>
I'm still a bit fuzzy on exactly how this section works, butwhat I do know is that the <model>variable is what tells Magento where your class is. I think theresource name can be whatever you like, and I'm not sure where themodule attribute is used as I seem to be able to set it to anythingI like and it still works.
Finally, let's look at the API method itself, here are thecontents ofmagento/app/code/local/CompanyName/ModuleName/Model/ObjectModel/Api.php:
<?php class CompanyName_ModuleName_Model_ObjectModel_Api extends Mage_Api_Model_Resource_Abstract { public function methodName($arg) { return "Hello World, here is my argument: " . $arg; } } ?>
And there you have it! You can call your method usingresource_name.methodName like you would any other API call.
Note: if you have Magento caching turned on, you will need torefresh the cache under System -> Cache Managementbefore the changes to your model will take effect. This caught meout a few times as changes I'd made were not being reflected in thedebug output, very frustrating! For debugging purposes I wouldsuggest turning the caching off temporarily.