Latest Tweets

Adobe Air, I want to introduce you to Magento

After my first hello world post using Adobe Flash Builder 4.5.1, I wanted to push a little bit further and try to create a small mobile app that interacts with Magento. If you don’t have Flash Builder 4.5.1, you can get a trial from Adobe at http://www.adobe.com/products/flashbuilder/

Magento is rapid growing open source platform for ecommerce, if you don't have it, you can get the community version from http://www.magentocommerce.com/download. Installing Magento could it be a little bit tricky, but there is plenty of information in the web. I've found that the best solution for this kind of POC is to have a virtual machine (virtual box) running Ubuntu desktop and have Magento running on that machine. It will also necessary to have the Sample data installed. Here is a link to start http://www.amicontech.com/blog/setting-up-magento-on-ubuntu/

 

Accessing the API

Once you have Magento up and running, you will need to set up a user with grants to access the API:

http://www.magentocommerce.com/boards/viewthread/23208/

Goto:  System -> Web Services -> Roles and define a Role set for your API user with the allowed actions.

For testing purposes you may create a temporary “can do everything” role first, and if things work nice, change that role to be as restrictive as necessary.

Save that Role and head over to: System > Web Services > Users

Add a new User, the username is your “api user”, and the key (~ password) is the “api key”

Assign a Role in the second tab and Save.

 

Create a Flex Mobile Project

Open Flash builder and create a Flex Mobile Project by choosing File -> New -> Flex Mobile Project. This will open the wizard, which we will use to create the project.

On the Project Location screen, we are going to set up the project name (MagentoMobilePOC), location and Flex SDK.

On the Mobile Settings screen, we are going to select settings specific to the target platform, for now, just select "Apple iOS" and "View Based Application" as a template

On the Server Settings screen, we are going to select NONE as the application server type; we are going to add the service reference latter on.

On the Build paths screen, we are going to set the application ID. This ID should be unique, reverse domain naming convention works like a charm!

 

The web service's client

On the Data / Services tab, click on the link "Connect to Data/Service...". On the next page, select Web Service (WSDL) and add the magento api url on the next page: http://your_magento_host/magento/api/v2_soap?wsdl=1 (where your_magento_host is the url where your local copy of magento is running), change the service name to "magento" (without the quotes) and the Data type package to "model" (again, without the quotes) and click on next.

From the operations to import, unselect all and select just the following and click on Finish

  • login(username:String, apiKey:string):string
  • customerCustomerList(sessionId:string, filters:Filters):customerCustomerEntityArray
  • customerCustomerCreate(sessionId:string, customerData:custoemrCustomerEntityToCreate):int

Flash builder will create the required classes with the code to interact with Magento.

 

Login View

This is not going to be a part of an actual application, but it will let us enter different combinations of user and password to test.

Open the MagentoMobilePOCHomeView.mxml file, and add a couple of text boxes, a button and a label with the following id: txtUsername, txtPassword, btnLogin and lblMessage.

HomeView

Select the btnLogin and select "Generate Event Handler" from the On click event, it will add the method stub to handle the click event

From the Data/Services tab, right click on the login web method, and click on "Generate Service Call", it will add the code to call the login web method.

Web service calls on Adobe Air are asynchronous, so we need to setup a kind of “callback” function to handle the result (and the fault), let’s add these two pieces of code. Modify the following line:

<s:CallResponder id="loginResult"/>

Write “result” (without the quotes) before the backslash, the IDE should give you the option to create the result event handler if you double click on, click on “Generate Event Handler”, it will add a stub method to handle the service call result. Do the same for the fault event handler. If the IDE is not giving you the option, try again or add the code by hand… the IDE it’s not quite consistent and I really hope they improve it a lot. Being used to work in MS Visual Studio 2008 / 2010 I took this little things for granted and is somehow frustrating to not have the same response from the IDE doing the same thingsResult Event Handler

Customer  List View

Let’s add a new View to show the customer List, right click on the “view” package and add a new MXML Component with CustomerListView as name. Add a label (lblMessage) a List (lstCustomer) and three buttons (btnBack, btnAdd, btnRefresh). Add an event handler for each of the button click events. Also, generate the service call for the customerCustomerList web method.

Customer View

Add the following code to the <fx:Declarations> section

<s:ArrayCollection id="customers">

</s:ArrayCollection>

We are going to use it to contain the list of customers we are going to receive from the web method.

Also, modify the List declaration adding these two parameters to bind the list with the customer array collection:

dataProvider="{customers}" labelField="email"

Generate the service call for the customerCustomerList web method and add the event handlers for the result and fault.

 

Customer Details View

Let’s add a new View to add a customer with CustomerDetailView as a name. Add a label (lblMessage), four text inputs (txtLastName, txtFirstName, txtEmail and txtPassword) and two buttons (btnBack and btnSave), you can also set the “prompt”  property of each text input to give the user a hint of what the application is expecting to receive on those fields. For the password text box, there is a “displayAsPasword” property that will hide the characters. We are not going to go into validation in this example.

Generate the service call for the customerCustomerCreate web method and add the event handlers for the result and fault.

Customer Detail

Navigation

The application flow should be, from the home view, once the user sets the username, password and tap on the login button; we should go to the CustomerListView and list the magento customers. If the user clicks on Add, we should go to the CustomerDetailView, on this view, if the user taps on back or successfully save the new customer, we go back to the CustomerListView. From here, we can go back to the home view or add a new customer. Let’s add the code to make the navigation happen.

On the home view, go to the btnLogin_clickHandlerevent handler and add the following code, while you are at it, take a look at the optional second parameter (data)… we are going to use it later ;)

navigator.pushView(CustomerListView);

On the CustomerListView, go to the btnBack_clickHandler and add the following code:

navigator.popView();

On the same view, go to the btnAdd_clickHandler and add the following code:

navigator.pushView(CustomerDetailView);

On the CustomerDetailView, go to the  btnSave_clickHandler and add the following code:

navigator.popView();

Do same for the btnBack_clickHandler handler.

Try it on the emulator, you will be able to go back and forth from each one of the application views, starting from the login.

 

Hi Magento, my name is Adobe Air, nice to meet you.

We have the UI and the navigation implemented, let see if we can talk “magento” ;)

On the HomeView:  go to the btnLogin_clickHandler and replace the navigation code with the following

navigator.pushView(CustomerListView);

Next, go to the loginResult_faultHandler and add the following, we are going to show whatever error we may get from magento on the lblMessage

lblMessage.text = event.fault.faultString;

Next, go to the loginResult_resultHandler and add the following:

navigator.pushView(CustomerListView, event.result.toString());

What are we doing here is to push the new view on the navigator and passing the result of the login (a retrieved from magento SessionId)

Here is the full code of the HomeView:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:magento="services.magento.*"
title="Customer Detail"
add="customerDetailView_addHandler(event)">
  <fx:Script>
    <![CDATA[
    import model.CustomerCustomerEntityToCreate;
    import mx.events.FlexEvent;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    protected var sessionId:String;
    protected function customerCustomerCreate(sessionId:String, customerData:CustomerCustomerEntityToCreate):void{
      customerCustomerCreateResult.token = magento.customerCustomerCreate(sessionId, customerData);
    }
    protected function customerCustomerCreateResult_resultHandler(event:ResultEvent):void{
      navigator.popView();
    }
    protected function customerCustomerCreateResult_faultHandler(event:FaultEvent):void{
      lblMessage.text = event.fault.faultString;
    }
    protected function btnSave_clickHandler(event:MouseEvent):void{
      var customerData:CustomerCustomerEntityToCreate = new CustomerCustomerEntityToCreate();
      customerData.lastname = txtLastName.text;
      customerData.firstname = txtFirstName.text;
      customerData.email = txtEmail.text;
      customerData.password = txtPassword.text;
      customerCustomerCreate(sessionId, customerData)
    }
    protected function btnBack_clickHandler(event:MouseEvent):void{
      navigator.popView();
    }
    protected function customerDetailView_addHandler(event:FlexEvent):void{
      sessionId = data.toString();
    }
    ]]>
  </fx:Script>
  <fx:Declarations>
    <s:CallResponder id="customerCustomerCreateResult" result="customerCustomerCreateResult_resultHandler(event)" fault="customerCustomerCreateResult_faultHandler(event)"/>
    <magento:Magento id="magento"/>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
  </fx:Declarations>
  <s:navigationContent>
    <s:Button id="btnBack" label="Back" click="btnBack_clickHandler(event)"/>
  </s:navigationContent>
  <s:actionContent>
    <s:Button id="btnSave" label="OK" click="btnSave_clickHandler(event)"/>
  </s:actionContent>
  <s:TextInput id="txtLastName" x="22" y="40" prompt="Last Name"/>
  <s:TextInput id="txtFirstName" x="22" y="114" prompt="First Name"/>
  <s:TextInput id="txtEmail" x="22" y="188" prompt="Email"/>
  <s:TextInput id="txtPassword" x="22" y="262" displayAsPassword="true" prompt="Password"/>
  <s:Label id="lblMessage" x="18" y="10" width="612" text="Label"/>
</s:View>

Let’s add the handler on the CustomerListView to manage the “add” event and take note of the session ID retrieved on the login, since we are going to need for any further call to magento.

Open the CustomerListView, on the definition node <s:View…> add a handler for the “add” event as we did for the result and fault for the services. Cross your fingers and hope the IDE helps you ;)

Change the orginal name (view1_addHandler) for something more useful (customerListView_addHandler) . To do that, select the whole handler name and press Ctrl + Alt + R, a dialog box asking for the new name will appear, once you click on Ok, all references to the old name will be replaced with the new oneJ, replace the event handler code with the following (we are declaring a string variable to hold the session id and also calling the customer list web method)

protected var sessionId : String;

protected function customerListView_addHandler(event:FlexEvent):void

{

                sessionId = data.toString();        

}

Here is the rest of the code, binding the customer result and showing the error message if any:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:s="library://ns.adobe.com/flex/spark"xmlns:magento="services.magento.*"title="Customers List" add="customerListView_addHandler(event)" >
  <fx:Script>
    <![CDATA[
      import model.Filters;
      import mx.events.FlexEvent;
      import mx.rpc.events.FaultEvent;
      import mx.rpc.events.ResultEvent;
     
      protected var sessionId : String;
     
      protected function btnBack_clickHandler(event:MouseEvent):void{
        navigator.popView();
      }
      protected function btnAdd_clickHandler(event:MouseEvent):void{
        navigator.pushView(CustomerDetailView, sessionId);
      }
      protected function btnRefresh_clickHandler(event:MouseEvent):void{
        customerCustomerList(sessionId, new Filters());
      }
      protected function customerCustomerList(sessionId:String, filters:Filters):void{
        customerCustomerListResult.token = magento.customerCustomerList(sessionId, filters);
      }
      protected function customerCustomerListResult_resultHandler(event:ResultEvent):void{
        var result:ArrayCollection = event.result as ArrayCollection;
        customers = result;
      }
      protected function customerCustomerListResult_faultHandler(event:FaultEvent):void{
        lblMessage.text = event.fault.faultString;
      }
      protected function customerListView_addHandler(event:FlexEvent):void{
        sessionId = data.toString();
        customerCustomerList(sessionId, new Filters());
      }
      ]]>
  </fx:Script>
  <fx:Declarations>
    <s:CallResponder id="customerCustomerListResult" result="customerCustomerListResult_resultHandler(event)" fault="customerCustomerListResult_faultHandler(event)"/>
    <magento:Magento id="magento"/>
    <s:ArrayCollection id="customers"></s:ArrayCollection>
    <s:CallResponder id="customerCustomerListResult2"/>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
  </fx:Declarations>
  <s:navigationContent>
    <s:Button id="btnBack" label="Back" click="btnBack_clickHandler(event)"/>
  </s:navigationContent>
  <s:actionContent>
    <s:Button id="btnAdd" label="Add" click="btnAdd_clickHandler(event)"/>
  </s:actionContent>
  <s:Label id="lblMessage" x="10" y="10" width="620" text="Label"/>
  <s:List id="lstCustomer" x="10" y="48" width="620" height="579" dataProvider="{customers}" labelField="email" ></s:List>
  <s:Button id="btnRefresh" x="470" y="635" label="Refresh" click="btnRefresh_clickHandler(event)"/>
</s:View>

Adding a new Customer, here is the code for the CustomerDetailView:

<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"xmlns:s="library://ns.adobe.com/flex/spark"xmlns:magento="services.magento.*"title="Customer Detail" add="customerDetailView_addHandler(event)">
  <fx:Script>
    <![CDATA[
        import model.CustomerCustomerEntityToCreate;
        import mx.events.FlexEvent;
        import mx.rpc.events.FaultEvent;
        import mx.rpc.events.ResultEvent;
       
        protected var sessionId:String;
       
        protected function customerCustomerCreate(sessionId:String, customerData:CustomerCustomerEntityToCreate):void{
          customerCustomerCreateResult.token = magento.customerCustomerCreate(sessionId, customerData);
        }
        protected function customerCustomerCreateResult_resultHandler(event:ResultEvent):void{
          navigator.popView();
        }
        protected function customerCustomerCreateResult_faultHandler(event:FaultEvent):void{
          lblMessage.text = event.fault.faultString;
        }
        protected function btnSave_clickHandler(event:MouseEvent):void{
          var customerData:CustomerCustomerEntityToCreate = new CustomerCustomerEntityToCreate();
          customerData.lastname = txtLastName.text;
          customerData.firstname = txtFirstName.text;
          customerData.email = txtEmail.text;
          customerData.password = txtPassword.text;
          customerCustomerCreate(sessionId, customerData)
        }
        protected function btnBack_clickHandler(event:MouseEvent):void{
          navigator.popView();
        }
        protected function customerDetailView_addHandler(event:FlexEvent):void{
          sessionId = data.toString();
        }
        ]]>
     </fx:Script>
  <fx:Declarations>
    <s:CallResponder id="customerCustomerCreateResult" result="customerCustomerCreateResult_resultHandler(event)" fault="customerCustomerCreateResult_faultHandler(event)"/>
    <magento:Magento id="magento"/>
    <!-- Place non-visual elements (e.g., services, value objects) here -->
  </fx:Declarations>
  <s:navigationContent>
    <s:Button id="btnBack" label="Back" click="btnBack_clickHandler(event)"/>
  </s:navigationContent>
  <s:actionContent>
    <s:Button id="btnSave" label="OK" click="btnSave_clickHandler(event)"/>
  </s:actionContent>
  <s:TextInput id="txtLastName" x="22" y="40" prompt="Last Name"/>
  <s:TextInput id="txtFirstName" x="22" y="114" prompt="First Name"/>
  <s:TextInput id="txtEmail" x="22" y="188" prompt="Email"/>
  <s:TextInput id="txtPassword" x="22" y="262" displayAsPassword="true" prompt="Password"/>
  <s:Label id="lblMessage" x="18" y="10" width="612" text="Label"/>
</s:View>

Try it, I had a couple of customers added to my local magento, you can check it by accessing the admin section of magento an going to Customers

Hope it helps you making your mobile applications to talk with Magento =)

Author

Project Manager
Seasoned Professional with 15+ years experience on the Technology Industry.

Add comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.