Magento API – ett exempel i PHP

soapDu kan kommunicera med Magento via dess API och till exempel hämta ut ett urval av produkter. Lägga ordrar och allt annat du kan tänka dig. Det här är perfekt om du vill koppla ihop två olika plattformar, till exempel Magento och en app, eller hämta ordrar från Magento in i ett ekonomisystem, eller få din kampanjsite att hämta data från Magento.

Målet med den här övningen är att ge produkt ID till Magento och få ut data om den produktens relaterade produkter genom att använda Magentos API.
Inspiration kommer från certifieringsfrågorna för Magento och från den här hemsidan.

Skapa API användare

I Magento admin kan du sätta upp ett användarkonto under menyn ”System” >> ”Web services” >> ”SOAP/XML-RPC users”. Hitta på ett namn och ett lösenord. Jag valde namnet ”test” och lösenordet ”testtest123”.
Därefter skapade jag en ”roll”, döpte den till ”Admins” och tilldelade alla rättigheter. Min användare fick vara medlem i den rollen.

Nu är allt uppsatt för att du ska kunna kommunicera med Magentos API.
Jag använder Magento CE 1.9.1.0 på min lokala dator som kör Ubuntu 14.10, Apache, PHP, MySQL, Xdebug, PHP Storm.

Du kan kommunicera med Magentos API på tre sätt. XML-RPC och SOAP, samt REST. Jag kommer beskriva och ge exempel på de två första metoderna och behandla REST i en senare artikel.

Produkter

Först behöver du produkter. Jag har lagt upp två simpla produkter i Magento. De har produkt ID 1 och 2.
Produkt ID 2 har fått en relaterad produkt, det är produkt ID 1 som är den relaterade produkten.
Tanken är nu att ga produkt id 2 till Magento och få tillbaka data om alla relaterade produkter, vilket i det här faller bara är en produkt, och den har ID 1.

 

RelateradProdukt

Exempelkod

Vi går direkt på exempelkoden som först kör XML-RPC och sedan SOAP v 1.

<?php
$apiUser = 'test';
$apiKey = 'testtest123';

$apiUrl = 'https://charzam.com/magento19/index.php/api/xmlrpc';
require_once 'app/Mage.php';
umask(0);
Mage::app();
$client = new Zend_XmlRpc_Client($apiUrl);
$sessionId = $client->call('login', array($apiUser, $apiKey));
try {
    $response = $client->call('call', array($sessionId, 'catalog_product_link.list', array('related', '2')));
    var_dump($response);
} catch (Exception $e) {
    echo $e->getMessage();
}

$apiUrl = 'https://charzam.com/magento19/index.php/api/soap?wsdl';
$client = new SoapClient($apiUrl);
$sessionId = $client->login($apiUser, $apiKey);
// $client->__setCookie('XDEBUG_SESSION','netbeans-xdebug11');
// $client->__setCookie('XDEBUG_SESSION_START','netbeans-xdebug11');
try {
    $response = $client->call($sessionId, 'catalog_product_link.list', array('related', '2'));
    var_dump($response);
} catch (Exception $e) {
    echo $e->getMessage();
}
$client->endSession($sessionId);

Testa

Du kan nu testa detta med en lämplig URL. Jag har lagt min exempelfil här:

https://charzam.com/magento19/test.php

Resultatet

Och resultatet om allt gick bra:

array (size=1)
  0 => 
    array (size=5)
      'product_id' => string '1' (length=1)
      'type' => string 'simple' (length=6)
      'set' => string '4' (length=1)
      'sku' => string 'hulk' (length=4)
      'position' => string '0' (length=1)
array (size=1)
  0 => 
    array (size=5)
      'product_id' => string '1' (length=1)
      'type' => string 'simple' (length=6)
      'set' => string '4' (length=1)
      'sku' => string 'hulk' (length=4)
      'position' => string '0' (length=1)

Första arrayern kommer från XML-RPC och den andra från SOAP.
Du ser att vi får Arrayer tillbaka. Du kan då komma åt ett värde så här:

if ($response[0][’type’] === ’simple) {

Debugga

Det ser ju ut att vara rätt, men hur kan man debugga detta? Du kan enkelt debugga ditt program med xdebug precis som vanligt. Det svåra i det här fallet är att vi vill debugga den andra ändan, själva Magento när den får förfrågan och vad den gör med den.

För att kunna trigga en annan xdebug session så finns de två bortkommenterade raderna:

// $client->__setCookie('XDEBUG_SESSION','netbeans-xdebug11');
 // $client->__setCookie('XDEBUG_SESSION_START','netbeans-xdebug11');

Som du ser har de inte namnet ’netbeans-xdebug’ som jag brukar använda utan istället ett annat namn. Vi kan nu debugga båda sidor av detta, både vårat program och Magentosidan.

Visst, exempelkoden ligger i samma mapp som Magento på web-servern men de kommunicerar bara via APIet så om du sätter brytpunkter i Magentokoden så kommer de inte att användas förrän du har med de här två raderna.

Var i Magento kan du debugga?
I det här fallet använder vi  ”catalog_product_link.list”, du hittar den rätta funktionen i:
app/code/core/Mage/Catalog/Model/Product/Link/Api.php

app/code är där all kod ligger, detta är en core funktion och alla core moduler startar med Mage.
Vi ska in i modulen Mage_Catalog och titta på dess Model: Product/Link och dess API.

Här i hittar du funktionen:

public function items($type, $productId, $identifierType = null)

Sätt en brytpunkt på första raden i funktionen, kommentera in de två setCookie-raderna i exempelkoden och kör exempelkoden igen.
Du kommer att märka att körningen fastnar trots att du inte har några brytpunkter i exempelkoden. Tryck på ”stop” för att avbryta debuggingen, då händer det grejer, din brytpunkt i core koden dyker upp och du kan debugga serversidan och se vad som händer.

SOAP V2

I exemplet ovan har vi använt SOAP v1. Det finns också SOAP v2 och här kommer ett exempel:

<?php
$apiUser = 'test';
$apiKey = 'testtest123';
$apiUrl = 'https://charzam.com/magento19/index.php/api/v2_soap?wsdl';
$client = new SoapClient($apiUrl);
$sessionId = $client->login($apiUser, $apiKey);
try {
 $response = $client->catalogProductLinkList($sessionId, 'related', '2');
 var_dump($response);
} catch (Exception $e) {
 echo $e->getMessage();
}
$client->endSession($sessionId);

Resultat

array (size=1)
  0 => 
    object(stdClass)[53]
      public 'product_id' => string '1' (length=1)
      public 'type' => string 'simple' (length=6)
      public 'set' => string '4' (length=1)
      public 'sku' => string 'hulk' (length=4)
      public 'position' => string '0' (length=1)

Som du ser ovan får vi en array tillbaka men varje produkt är en standradklass. Du kan använda resultatet så här:

if ($response[0]->type === 'simple') {

Hastighet

Jag märkte att SOAP V2 är märkbart långsammare och blev nyfiken över hur snabb varje metod är. Därför lade jag in lite mätkod mellan varje metod och fick fram ett resultat.

$startTime = microtime(true);
...
$endTime = microtime(true) - $startTime;
$speed['xml-rpc'] = $endTime;

Resultatet blev:

array (size=3)
 'xml-rpc' => float 0.28335785865784
 'SOAP-v1' => float 0.39153599739075
 'SOAP-v2' => float 3.5304019451141

Det är mycket spännande att se varför det är så långsamt. Därför kommenterade jag bort själva funktionsanropet på SOAP v2 och bara sparade initialiseringen för att få ett sessionId.

’SOAP-v2’ => float 2.0124518871307

Har kört det flera gånger och får ca 2 sekunder. Har även testat att köra SOAP v2 först men med samma resultat.

Därefter har jag enbart mätt tiden på funktionsanropet ”catalogProductLinkList” och får ca 1 sekund.

Det finns en fråga på nätet om just detta, och svaret är att slå på cache, så vi gör väl det då. Attans, Magentocachen var påslagen. Jag slår av den och testar:

array (size=3)
 'xml-rpc' => float 1.5424790382385
 'SOAP-v1' => float 1.8732810020447
 'SOAP-v2' => float 28.166204929352

Det blev väldigt illa. SOAP v2 gör ganska mycket extragrejer som att samla ihop olika WSDL scheman och bygga ihop ett svar. Men är det inget vi kan göra? Jo det finns ett trick kvar, vi kan cacha byggandet av WSDL. Jag slår på Magento cachen och lägger till detta i exemplet på både SOAP v1 och SOAP v2:

$soapParameters = array(
 'cache_wsdl' => WSDL_CACHE_BOTH,
 'connection_timeout' => 120
);
$client = new SoapClient($apiUrl, $soapParameters);

Och resultatet blir efter några körningar runt dessa siffror:

array (size=3)
 'xml-rpc' => float 0.31184816360474
 'SOAP-v1' => float 0.35092878341675
 'SOAP-v2' => float 3.1439740657806

Slutsats om hastigheten

Min slutsats är att SOAP v2 alltid är rejält långsammare trots cachening etc. I vårt fall använder vi språket PHP som kan byta datatyp på variabler. Då fungerar det att ha SOAP v1. Men kör vi ett starkt typat språk, då behövs SOAP v2.

Den generella regeln är att undvika göra saker tills det verkligen behövs. Även SOAP v1 och XML-RPC är ganska långsamma i sammanhanget.

Tänk att du har en Magento handelsplats med massor av besökare. Du har lagt in så att produktsidan alltid visar aktuellt lagersaldo. Lagersaldot kommer från en extern tjänst via ett API och nu stormar REA-sugna slutkunder din site. 10.000 på en gång tittar på olika produkter och får en extra väntetid på 0.3 sekunder varje gång de tittar på en produkt.

Realtidssaldo i all ära men du skulle i detta läget vinna på att undvika fråga APIet efter lagersaldo och återanvända det gamla värdet i någon minut eller två. Om kunden kommer till kassan görs det en ny lagersaldokoll i alla fall.

Magento API dokumentation

Magento API finns dokumenterad här. Här finns både SOAP och REST dokumenterat.

Nästa steg för mig är att utforska APIet mer. Det finns så många användningsområden.

Du kan även testa det exempel jag gjort i Python som gör samma sak som exemplen ovan, med SOAP v2.

Jag ska även försöka mig på ett REST-exempel. Jag har använt REST APIer tidigare men inte mot Magentos REST API.

EOD